161766fe9SRichard Henderson /* 261766fe9SRichard Henderson * HPPA emulation cpu translation for qemu. 361766fe9SRichard Henderson * 461766fe9SRichard Henderson * Copyright (c) 2016 Richard Henderson <rth@twiddle.net> 561766fe9SRichard Henderson * 661766fe9SRichard Henderson * This library is free software; you can redistribute it and/or 761766fe9SRichard Henderson * modify it under the terms of the GNU Lesser General Public 861766fe9SRichard Henderson * License as published by the Free Software Foundation; either 961766fe9SRichard Henderson * version 2 of the License, or (at your option) any later version. 1061766fe9SRichard Henderson * 1161766fe9SRichard Henderson * This library is distributed in the hope that it will be useful, 1261766fe9SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 1361766fe9SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1461766fe9SRichard Henderson * Lesser General Public License for more details. 1561766fe9SRichard Henderson * 1661766fe9SRichard Henderson * You should have received a copy of the GNU Lesser General Public 1761766fe9SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1861766fe9SRichard Henderson */ 1961766fe9SRichard Henderson 2061766fe9SRichard Henderson #include "qemu/osdep.h" 2161766fe9SRichard Henderson #include "cpu.h" 2261766fe9SRichard Henderson #include "disas/disas.h" 2361766fe9SRichard Henderson #include "qemu/host-utils.h" 2461766fe9SRichard Henderson #include "exec/exec-all.h" 2561766fe9SRichard Henderson #include "tcg-op.h" 2661766fe9SRichard Henderson #include "exec/cpu_ldst.h" 2761766fe9SRichard Henderson #include "exec/helper-proto.h" 2861766fe9SRichard Henderson #include "exec/helper-gen.h" 29869051eaSRichard Henderson #include "exec/translator.h" 3061766fe9SRichard Henderson #include "trace-tcg.h" 3161766fe9SRichard Henderson #include "exec/log.h" 3261766fe9SRichard Henderson 3361766fe9SRichard Henderson typedef struct DisasCond { 3461766fe9SRichard Henderson TCGCond c; 3561766fe9SRichard Henderson TCGv a0, a1; 3661766fe9SRichard Henderson bool a0_is_n; 3761766fe9SRichard Henderson bool a1_is_0; 3861766fe9SRichard Henderson } DisasCond; 3961766fe9SRichard Henderson 4061766fe9SRichard Henderson typedef struct DisasContext { 41d01a3625SRichard Henderson DisasContextBase base; 4261766fe9SRichard Henderson CPUState *cs; 4361766fe9SRichard Henderson 4461766fe9SRichard Henderson target_ulong iaoq_f; 4561766fe9SRichard Henderson target_ulong iaoq_b; 4661766fe9SRichard Henderson target_ulong iaoq_n; 4761766fe9SRichard Henderson TCGv iaoq_n_var; 4861766fe9SRichard Henderson 4961766fe9SRichard Henderson int ntemps; 5061766fe9SRichard Henderson TCGv temps[8]; 5161766fe9SRichard Henderson 5261766fe9SRichard Henderson DisasCond null_cond; 5361766fe9SRichard Henderson TCGLabel *null_lab; 5461766fe9SRichard Henderson 5561766fe9SRichard Henderson bool psw_n_nonzero; 5661766fe9SRichard Henderson } DisasContext; 5761766fe9SRichard Henderson 58869051eaSRichard Henderson /* Target-specific return values from translate_one, indicating the 59869051eaSRichard Henderson state of the TB. Note that DISAS_NEXT indicates that we are not 60869051eaSRichard Henderson exiting the TB. */ 6161766fe9SRichard Henderson 6261766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 6361766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 64869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 6561766fe9SRichard Henderson 6661766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 6761766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 68869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 6961766fe9SRichard Henderson 7061766fe9SRichard Henderson typedef struct DisasInsn { 7161766fe9SRichard Henderson uint32_t insn, mask; 72869051eaSRichard Henderson DisasJumpType (*trans)(DisasContext *ctx, uint32_t insn, 7361766fe9SRichard Henderson const struct DisasInsn *f); 74b2167459SRichard Henderson union { 75eff235ebSPaolo Bonzini void (*ttt)(TCGv, TCGv, TCGv); 76eff235ebSPaolo Bonzini void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32); 77eff235ebSPaolo Bonzini void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64); 78eff235ebSPaolo Bonzini void (*wew)(TCGv_i32, TCGv_env, TCGv_i32); 79eff235ebSPaolo Bonzini void (*ded)(TCGv_i64, TCGv_env, TCGv_i64); 80eff235ebSPaolo Bonzini void (*wed)(TCGv_i32, TCGv_env, TCGv_i64); 81eff235ebSPaolo Bonzini void (*dew)(TCGv_i64, TCGv_env, TCGv_i32); 82eff235ebSPaolo Bonzini } f; 8361766fe9SRichard Henderson } DisasInsn; 8461766fe9SRichard Henderson 8561766fe9SRichard Henderson /* global register indexes */ 8661766fe9SRichard Henderson static TCGv_env cpu_env; 8761766fe9SRichard Henderson static TCGv cpu_gr[32]; 8861766fe9SRichard Henderson static TCGv cpu_iaoq_f; 8961766fe9SRichard Henderson static TCGv cpu_iaoq_b; 9061766fe9SRichard Henderson static TCGv cpu_sar; 9161766fe9SRichard Henderson static TCGv cpu_psw_n; 9261766fe9SRichard Henderson static TCGv cpu_psw_v; 9361766fe9SRichard Henderson static TCGv cpu_psw_cb; 9461766fe9SRichard Henderson static TCGv cpu_psw_cb_msb; 9561766fe9SRichard Henderson static TCGv cpu_cr26; 9661766fe9SRichard Henderson static TCGv cpu_cr27; 9761766fe9SRichard Henderson 9861766fe9SRichard Henderson #include "exec/gen-icount.h" 9961766fe9SRichard Henderson 10061766fe9SRichard Henderson void hppa_translate_init(void) 10161766fe9SRichard Henderson { 10261766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 10361766fe9SRichard Henderson 10461766fe9SRichard Henderson typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar; 10561766fe9SRichard Henderson static const GlobalVar vars[] = { 10661766fe9SRichard Henderson DEF_VAR(sar), 10761766fe9SRichard Henderson DEF_VAR(cr26), 10861766fe9SRichard Henderson DEF_VAR(cr27), 10961766fe9SRichard Henderson DEF_VAR(psw_n), 11061766fe9SRichard Henderson DEF_VAR(psw_v), 11161766fe9SRichard Henderson DEF_VAR(psw_cb), 11261766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 11361766fe9SRichard Henderson DEF_VAR(iaoq_f), 11461766fe9SRichard Henderson DEF_VAR(iaoq_b), 11561766fe9SRichard Henderson }; 11661766fe9SRichard Henderson 11761766fe9SRichard Henderson #undef DEF_VAR 11861766fe9SRichard Henderson 11961766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 12061766fe9SRichard Henderson static const char gr_names[32][4] = { 12161766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 12261766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 12361766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 12461766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 12561766fe9SRichard Henderson }; 12661766fe9SRichard Henderson 12761766fe9SRichard Henderson int i; 12861766fe9SRichard Henderson 12961766fe9SRichard Henderson cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); 13061766fe9SRichard Henderson tcg_ctx.tcg_env = cpu_env; 13161766fe9SRichard Henderson 13261766fe9SRichard Henderson TCGV_UNUSED(cpu_gr[0]); 13361766fe9SRichard Henderson for (i = 1; i < 32; i++) { 13461766fe9SRichard Henderson cpu_gr[i] = tcg_global_mem_new(cpu_env, 13561766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 13661766fe9SRichard Henderson gr_names[i]); 13761766fe9SRichard Henderson } 13861766fe9SRichard Henderson 13961766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 14061766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 14161766fe9SRichard Henderson *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name); 14261766fe9SRichard Henderson } 14361766fe9SRichard Henderson } 14461766fe9SRichard Henderson 145129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 146129e9cc3SRichard Henderson { 147129e9cc3SRichard Henderson DisasCond r = { .c = TCG_COND_NEVER }; 148129e9cc3SRichard Henderson TCGV_UNUSED(r.a0); 149129e9cc3SRichard Henderson TCGV_UNUSED(r.a1); 150129e9cc3SRichard Henderson return r; 151129e9cc3SRichard Henderson } 152129e9cc3SRichard Henderson 153129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 154129e9cc3SRichard Henderson { 155129e9cc3SRichard Henderson DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true }; 156129e9cc3SRichard Henderson r.a0 = cpu_psw_n; 157129e9cc3SRichard Henderson TCGV_UNUSED(r.a1); 158129e9cc3SRichard Henderson return r; 159129e9cc3SRichard Henderson } 160129e9cc3SRichard Henderson 161129e9cc3SRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv a0) 162129e9cc3SRichard Henderson { 163129e9cc3SRichard Henderson DisasCond r = { .c = c, .a1_is_0 = true }; 164129e9cc3SRichard Henderson 165129e9cc3SRichard Henderson assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 166129e9cc3SRichard Henderson r.a0 = tcg_temp_new(); 167129e9cc3SRichard Henderson tcg_gen_mov_tl(r.a0, a0); 168129e9cc3SRichard Henderson TCGV_UNUSED(r.a1); 169129e9cc3SRichard Henderson 170129e9cc3SRichard Henderson return r; 171129e9cc3SRichard Henderson } 172129e9cc3SRichard Henderson 173129e9cc3SRichard Henderson static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1) 174129e9cc3SRichard Henderson { 175129e9cc3SRichard Henderson DisasCond r = { .c = c }; 176129e9cc3SRichard Henderson 177129e9cc3SRichard Henderson assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 178129e9cc3SRichard Henderson r.a0 = tcg_temp_new(); 179129e9cc3SRichard Henderson tcg_gen_mov_tl(r.a0, a0); 180129e9cc3SRichard Henderson r.a1 = tcg_temp_new(); 181129e9cc3SRichard Henderson tcg_gen_mov_tl(r.a1, a1); 182129e9cc3SRichard Henderson 183129e9cc3SRichard Henderson return r; 184129e9cc3SRichard Henderson } 185129e9cc3SRichard Henderson 186129e9cc3SRichard Henderson static void cond_prep(DisasCond *cond) 187129e9cc3SRichard Henderson { 188129e9cc3SRichard Henderson if (cond->a1_is_0) { 189129e9cc3SRichard Henderson cond->a1_is_0 = false; 190129e9cc3SRichard Henderson cond->a1 = tcg_const_tl(0); 191129e9cc3SRichard Henderson } 192129e9cc3SRichard Henderson } 193129e9cc3SRichard Henderson 194129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 195129e9cc3SRichard Henderson { 196129e9cc3SRichard Henderson switch (cond->c) { 197129e9cc3SRichard Henderson default: 198129e9cc3SRichard Henderson if (!cond->a0_is_n) { 199129e9cc3SRichard Henderson tcg_temp_free(cond->a0); 200129e9cc3SRichard Henderson } 201129e9cc3SRichard Henderson if (!cond->a1_is_0) { 202129e9cc3SRichard Henderson tcg_temp_free(cond->a1); 203129e9cc3SRichard Henderson } 204129e9cc3SRichard Henderson cond->a0_is_n = false; 205129e9cc3SRichard Henderson cond->a1_is_0 = false; 206129e9cc3SRichard Henderson TCGV_UNUSED(cond->a0); 207129e9cc3SRichard Henderson TCGV_UNUSED(cond->a1); 208129e9cc3SRichard Henderson /* fallthru */ 209129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 210129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 211129e9cc3SRichard Henderson break; 212129e9cc3SRichard Henderson case TCG_COND_NEVER: 213129e9cc3SRichard Henderson break; 214129e9cc3SRichard Henderson } 215129e9cc3SRichard Henderson } 216129e9cc3SRichard Henderson 21761766fe9SRichard Henderson static TCGv get_temp(DisasContext *ctx) 21861766fe9SRichard Henderson { 21961766fe9SRichard Henderson unsigned i = ctx->ntemps++; 22061766fe9SRichard Henderson g_assert(i < ARRAY_SIZE(ctx->temps)); 22161766fe9SRichard Henderson return ctx->temps[i] = tcg_temp_new(); 22261766fe9SRichard Henderson } 22361766fe9SRichard Henderson 22461766fe9SRichard Henderson static TCGv load_const(DisasContext *ctx, target_long v) 22561766fe9SRichard Henderson { 22661766fe9SRichard Henderson TCGv t = get_temp(ctx); 22761766fe9SRichard Henderson tcg_gen_movi_tl(t, v); 22861766fe9SRichard Henderson return t; 22961766fe9SRichard Henderson } 23061766fe9SRichard Henderson 23161766fe9SRichard Henderson static TCGv load_gpr(DisasContext *ctx, unsigned reg) 23261766fe9SRichard Henderson { 23361766fe9SRichard Henderson if (reg == 0) { 23461766fe9SRichard Henderson TCGv t = get_temp(ctx); 23561766fe9SRichard Henderson tcg_gen_movi_tl(t, 0); 23661766fe9SRichard Henderson return t; 23761766fe9SRichard Henderson } else { 23861766fe9SRichard Henderson return cpu_gr[reg]; 23961766fe9SRichard Henderson } 24061766fe9SRichard Henderson } 24161766fe9SRichard Henderson 24261766fe9SRichard Henderson static TCGv dest_gpr(DisasContext *ctx, unsigned reg) 24361766fe9SRichard Henderson { 244129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 24561766fe9SRichard Henderson return get_temp(ctx); 24661766fe9SRichard Henderson } else { 24761766fe9SRichard Henderson return cpu_gr[reg]; 24861766fe9SRichard Henderson } 24961766fe9SRichard Henderson } 25061766fe9SRichard Henderson 251129e9cc3SRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t) 252129e9cc3SRichard Henderson { 253129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 254129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 255129e9cc3SRichard Henderson tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0, 256129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 257129e9cc3SRichard Henderson } else { 258129e9cc3SRichard Henderson tcg_gen_mov_tl(dest, t); 259129e9cc3SRichard Henderson } 260129e9cc3SRichard Henderson } 261129e9cc3SRichard Henderson 262129e9cc3SRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t) 263129e9cc3SRichard Henderson { 264129e9cc3SRichard Henderson if (reg != 0) { 265129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 266129e9cc3SRichard Henderson } 267129e9cc3SRichard Henderson } 268129e9cc3SRichard Henderson 26996d6407fSRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 27096d6407fSRichard Henderson # define HI_OFS 0 27196d6407fSRichard Henderson # define LO_OFS 4 27296d6407fSRichard Henderson #else 27396d6407fSRichard Henderson # define HI_OFS 4 27496d6407fSRichard Henderson # define LO_OFS 0 27596d6407fSRichard Henderson #endif 27696d6407fSRichard Henderson 27796d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 27896d6407fSRichard Henderson { 27996d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 28096d6407fSRichard Henderson tcg_gen_ld_i32(ret, cpu_env, 28196d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 28296d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 28396d6407fSRichard Henderson return ret; 28496d6407fSRichard Henderson } 28596d6407fSRichard Henderson 286ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 287ebe9383cSRichard Henderson { 288ebe9383cSRichard Henderson if (rt == 0) { 289ebe9383cSRichard Henderson return tcg_const_i32(0); 290ebe9383cSRichard Henderson } else { 291ebe9383cSRichard Henderson return load_frw_i32(rt); 292ebe9383cSRichard Henderson } 293ebe9383cSRichard Henderson } 294ebe9383cSRichard Henderson 295ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 296ebe9383cSRichard Henderson { 297ebe9383cSRichard Henderson if (rt == 0) { 298ebe9383cSRichard Henderson return tcg_const_i64(0); 299ebe9383cSRichard Henderson } else { 300ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 301ebe9383cSRichard Henderson tcg_gen_ld32u_i64(ret, cpu_env, 302ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 303ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 304ebe9383cSRichard Henderson return ret; 305ebe9383cSRichard Henderson } 306ebe9383cSRichard Henderson } 307ebe9383cSRichard Henderson 30896d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 30996d6407fSRichard Henderson { 31096d6407fSRichard Henderson tcg_gen_st_i32(val, cpu_env, 31196d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 31296d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 31396d6407fSRichard Henderson } 31496d6407fSRichard Henderson 31596d6407fSRichard Henderson #undef HI_OFS 31696d6407fSRichard Henderson #undef LO_OFS 31796d6407fSRichard Henderson 31896d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 31996d6407fSRichard Henderson { 32096d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 32196d6407fSRichard Henderson tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt])); 32296d6407fSRichard Henderson return ret; 32396d6407fSRichard Henderson } 32496d6407fSRichard Henderson 325ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 326ebe9383cSRichard Henderson { 327ebe9383cSRichard Henderson if (rt == 0) { 328ebe9383cSRichard Henderson return tcg_const_i64(0); 329ebe9383cSRichard Henderson } else { 330ebe9383cSRichard Henderson return load_frd(rt); 331ebe9383cSRichard Henderson } 332ebe9383cSRichard Henderson } 333ebe9383cSRichard Henderson 33496d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 33596d6407fSRichard Henderson { 33696d6407fSRichard Henderson tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt])); 33796d6407fSRichard Henderson } 33896d6407fSRichard Henderson 339129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 340129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 341129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 342129e9cc3SRichard Henderson { 343129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 344129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 345129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 346129e9cc3SRichard Henderson 347129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 348129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 349129e9cc3SRichard Henderson 350129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 351129e9cc3SRichard Henderson if (ctx->null_cond.a0_is_n) { 352129e9cc3SRichard Henderson ctx->null_cond.a0_is_n = false; 353129e9cc3SRichard Henderson ctx->null_cond.a0 = tcg_temp_new(); 354129e9cc3SRichard Henderson tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n); 355129e9cc3SRichard Henderson } 356129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 357129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 358129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 359129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 360129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 361129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, 0); 362129e9cc3SRichard Henderson } 363129e9cc3SRichard Henderson 364129e9cc3SRichard Henderson tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0, 365129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 366129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 367129e9cc3SRichard Henderson } 368129e9cc3SRichard Henderson } 369129e9cc3SRichard Henderson 370129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 371129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 372129e9cc3SRichard Henderson { 373129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 374129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 375129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, 0); 376129e9cc3SRichard Henderson } 377129e9cc3SRichard Henderson return; 378129e9cc3SRichard Henderson } 379129e9cc3SRichard Henderson if (!ctx->null_cond.a0_is_n) { 380129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 381129e9cc3SRichard Henderson tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n, 382129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 383129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 384129e9cc3SRichard Henderson } 385129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 386129e9cc3SRichard Henderson } 387129e9cc3SRichard Henderson 388129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 389129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 390129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 391129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 392129e9cc3SRichard Henderson { 393129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 394129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, x); 395129e9cc3SRichard Henderson } 396129e9cc3SRichard Henderson } 397129e9cc3SRichard Henderson 398129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 399129e9cc3SRichard Henderson This is the pair to nullify_over. */ 400869051eaSRichard Henderson static DisasJumpType nullify_end(DisasContext *ctx, DisasJumpType status) 401129e9cc3SRichard Henderson { 402129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 403129e9cc3SRichard Henderson 404129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 405129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 406129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 407129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 408129e9cc3SRichard Henderson return status; 409129e9cc3SRichard Henderson } 410129e9cc3SRichard Henderson ctx->null_lab = NULL; 411129e9cc3SRichard Henderson 412129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 413129e9cc3SRichard Henderson /* The next instruction will be unconditional, 414129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 415129e9cc3SRichard Henderson gen_set_label(null_lab); 416129e9cc3SRichard Henderson } else { 417129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 418129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 419129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 420129e9cc3SRichard Henderson label we have the proper value in place. */ 421129e9cc3SRichard Henderson nullify_save(ctx); 422129e9cc3SRichard Henderson gen_set_label(null_lab); 423129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 424129e9cc3SRichard Henderson } 425129e9cc3SRichard Henderson 426869051eaSRichard Henderson assert(status != DISAS_NORETURN && status != DISAS_IAQ_N_UPDATED); 427869051eaSRichard Henderson if (status == DISAS_NORETURN) { 428869051eaSRichard Henderson status = DISAS_NEXT; 429129e9cc3SRichard Henderson } 430129e9cc3SRichard Henderson return status; 431129e9cc3SRichard Henderson } 432129e9cc3SRichard Henderson 43361766fe9SRichard Henderson static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval) 43461766fe9SRichard Henderson { 43561766fe9SRichard Henderson if (unlikely(ival == -1)) { 43661766fe9SRichard Henderson tcg_gen_mov_tl(dest, vval); 43761766fe9SRichard Henderson } else { 43861766fe9SRichard Henderson tcg_gen_movi_tl(dest, ival); 43961766fe9SRichard Henderson } 44061766fe9SRichard Henderson } 44161766fe9SRichard Henderson 44261766fe9SRichard Henderson static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp) 44361766fe9SRichard Henderson { 44461766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 44561766fe9SRichard Henderson } 44661766fe9SRichard Henderson 44761766fe9SRichard Henderson static void gen_excp_1(int exception) 44861766fe9SRichard Henderson { 44961766fe9SRichard Henderson TCGv_i32 t = tcg_const_i32(exception); 45061766fe9SRichard Henderson gen_helper_excp(cpu_env, t); 45161766fe9SRichard Henderson tcg_temp_free_i32(t); 45261766fe9SRichard Henderson } 45361766fe9SRichard Henderson 454869051eaSRichard Henderson static DisasJumpType gen_excp(DisasContext *ctx, int exception) 45561766fe9SRichard Henderson { 45661766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 45761766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 458129e9cc3SRichard Henderson nullify_save(ctx); 45961766fe9SRichard Henderson gen_excp_1(exception); 460869051eaSRichard Henderson return DISAS_NORETURN; 46161766fe9SRichard Henderson } 46261766fe9SRichard Henderson 463869051eaSRichard Henderson static DisasJumpType gen_illegal(DisasContext *ctx) 46461766fe9SRichard Henderson { 465129e9cc3SRichard Henderson nullify_over(ctx); 466129e9cc3SRichard Henderson return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL)); 46761766fe9SRichard Henderson } 46861766fe9SRichard Henderson 46961766fe9SRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ulong dest) 47061766fe9SRichard Henderson { 47161766fe9SRichard Henderson /* Suppress goto_tb in the case of single-steping and IO. */ 472c5a49c63SEmilio G. Cota if ((tb_cflags(ctx->base.tb) & CF_LAST_IO) || ctx->base.singlestep_enabled) { 47361766fe9SRichard Henderson return false; 47461766fe9SRichard Henderson } 47561766fe9SRichard Henderson return true; 47661766fe9SRichard Henderson } 47761766fe9SRichard Henderson 478129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 479129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 480129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 481129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 482129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 483129e9cc3SRichard Henderson { 484129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 485129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 486129e9cc3SRichard Henderson } 487129e9cc3SRichard Henderson 48861766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 48961766fe9SRichard Henderson target_ulong f, target_ulong b) 49061766fe9SRichard Henderson { 49161766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 49261766fe9SRichard Henderson tcg_gen_goto_tb(which); 49361766fe9SRichard Henderson tcg_gen_movi_tl(cpu_iaoq_f, f); 49461766fe9SRichard Henderson tcg_gen_movi_tl(cpu_iaoq_b, b); 495d01a3625SRichard Henderson tcg_gen_exit_tb((uintptr_t)ctx->base.tb + which); 49661766fe9SRichard Henderson } else { 49761766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b); 49861766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var); 499d01a3625SRichard Henderson if (ctx->base.singlestep_enabled) { 50061766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 50161766fe9SRichard Henderson } else { 5027f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 50361766fe9SRichard Henderson } 50461766fe9SRichard Henderson } 50561766fe9SRichard Henderson } 50661766fe9SRichard Henderson 507b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign, 508b2167459SRichard Henderson with the rest of the field becoming the least significant bits. */ 509b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len) 510b2167459SRichard Henderson { 511b2167459SRichard Henderson target_ulong x = -(target_ulong)extract32(val, pos, 1); 512b2167459SRichard Henderson x = (x << (len - 1)) | extract32(val, pos + 1, len - 1); 513b2167459SRichard Henderson return x; 514b2167459SRichard Henderson } 515b2167459SRichard Henderson 516ebe9383cSRichard Henderson static unsigned assemble_rt64(uint32_t insn) 517ebe9383cSRichard Henderson { 518ebe9383cSRichard Henderson unsigned r1 = extract32(insn, 6, 1); 519ebe9383cSRichard Henderson unsigned r0 = extract32(insn, 0, 5); 520ebe9383cSRichard Henderson return r1 * 32 + r0; 521ebe9383cSRichard Henderson } 522ebe9383cSRichard Henderson 523ebe9383cSRichard Henderson static unsigned assemble_ra64(uint32_t insn) 524ebe9383cSRichard Henderson { 525ebe9383cSRichard Henderson unsigned r1 = extract32(insn, 7, 1); 526ebe9383cSRichard Henderson unsigned r0 = extract32(insn, 21, 5); 527ebe9383cSRichard Henderson return r1 * 32 + r0; 528ebe9383cSRichard Henderson } 529ebe9383cSRichard Henderson 530ebe9383cSRichard Henderson static unsigned assemble_rb64(uint32_t insn) 531ebe9383cSRichard Henderson { 532ebe9383cSRichard Henderson unsigned r1 = extract32(insn, 12, 1); 533ebe9383cSRichard Henderson unsigned r0 = extract32(insn, 16, 5); 534ebe9383cSRichard Henderson return r1 * 32 + r0; 535ebe9383cSRichard Henderson } 536ebe9383cSRichard Henderson 537ebe9383cSRichard Henderson static unsigned assemble_rc64(uint32_t insn) 538ebe9383cSRichard Henderson { 539ebe9383cSRichard Henderson unsigned r2 = extract32(insn, 8, 1); 540ebe9383cSRichard Henderson unsigned r1 = extract32(insn, 13, 3); 541ebe9383cSRichard Henderson unsigned r0 = extract32(insn, 9, 2); 542ebe9383cSRichard Henderson return r2 * 32 + r1 * 4 + r0; 543ebe9383cSRichard Henderson } 544ebe9383cSRichard Henderson 54598cd9ca7SRichard Henderson static target_long assemble_12(uint32_t insn) 54698cd9ca7SRichard Henderson { 54798cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 54898cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 54998cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 55098cd9ca7SRichard Henderson return x; 55198cd9ca7SRichard Henderson } 55298cd9ca7SRichard Henderson 553b2167459SRichard Henderson static target_long assemble_16(uint32_t insn) 554b2167459SRichard Henderson { 555b2167459SRichard Henderson /* Take the name from PA2.0, which produces a 16-bit number 556b2167459SRichard Henderson only with wide mode; otherwise a 14-bit number. Since we don't 557b2167459SRichard Henderson implement wide mode, this is always the 14-bit number. */ 558b2167459SRichard Henderson return low_sextract(insn, 0, 14); 559b2167459SRichard Henderson } 560b2167459SRichard Henderson 56196d6407fSRichard Henderson static target_long assemble_16a(uint32_t insn) 56296d6407fSRichard Henderson { 56396d6407fSRichard Henderson /* Take the name from PA2.0, which produces a 14-bit shifted number 56496d6407fSRichard Henderson only with wide mode; otherwise a 12-bit shifted number. Since we 56596d6407fSRichard Henderson don't implement wide mode, this is always the 12-bit number. */ 56696d6407fSRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 56796d6407fSRichard Henderson x = (x << 11) | extract32(insn, 2, 11); 56896d6407fSRichard Henderson return x << 2; 56996d6407fSRichard Henderson } 57096d6407fSRichard Henderson 57198cd9ca7SRichard Henderson static target_long assemble_17(uint32_t insn) 57298cd9ca7SRichard Henderson { 57398cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 57498cd9ca7SRichard Henderson x = (x << 5) | extract32(insn, 16, 5); 57598cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 57698cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 57798cd9ca7SRichard Henderson return x << 2; 57898cd9ca7SRichard Henderson } 57998cd9ca7SRichard Henderson 580b2167459SRichard Henderson static target_long assemble_21(uint32_t insn) 581b2167459SRichard Henderson { 582b2167459SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 583b2167459SRichard Henderson x = (x << 11) | extract32(insn, 1, 11); 584b2167459SRichard Henderson x = (x << 2) | extract32(insn, 14, 2); 585b2167459SRichard Henderson x = (x << 5) | extract32(insn, 16, 5); 586b2167459SRichard Henderson x = (x << 2) | extract32(insn, 12, 2); 587b2167459SRichard Henderson return x << 11; 588b2167459SRichard Henderson } 589b2167459SRichard Henderson 59098cd9ca7SRichard Henderson static target_long assemble_22(uint32_t insn) 59198cd9ca7SRichard Henderson { 59298cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 59398cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 16, 10); 59498cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 59598cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 59698cd9ca7SRichard Henderson return x << 2; 59798cd9ca7SRichard Henderson } 59898cd9ca7SRichard Henderson 599b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of 600b2167459SRichard Henderson the conditions, without describing their exact implementation. The 601b2167459SRichard Henderson interpretations do not stand up well when considering ADD,C and SUB,B. 602b2167459SRichard Henderson However, considering the Addition, Subtraction and Logical conditions 603b2167459SRichard Henderson as a whole it would appear that these relations are similar to what 604b2167459SRichard Henderson a traditional NZCV set of flags would produce. */ 605b2167459SRichard Henderson 606b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv) 607b2167459SRichard Henderson { 608b2167459SRichard Henderson DisasCond cond; 609b2167459SRichard Henderson TCGv tmp; 610b2167459SRichard Henderson 611b2167459SRichard Henderson switch (cf >> 1) { 612b2167459SRichard Henderson case 0: /* Never / TR */ 613b2167459SRichard Henderson cond = cond_make_f(); 614b2167459SRichard Henderson break; 615b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 616b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 617b2167459SRichard Henderson break; 618b2167459SRichard Henderson case 2: /* < / >= (N / !N) */ 619b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, res); 620b2167459SRichard Henderson break; 621b2167459SRichard Henderson case 3: /* <= / > (N | Z / !N & !Z) */ 622b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LE, res); 623b2167459SRichard Henderson break; 624b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 625b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 626b2167459SRichard Henderson break; 627b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 628b2167459SRichard Henderson tmp = tcg_temp_new(); 629b2167459SRichard Henderson tcg_gen_neg_tl(tmp, cb_msb); 630b2167459SRichard Henderson tcg_gen_and_tl(tmp, tmp, res); 631b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, tmp); 632b2167459SRichard Henderson tcg_temp_free(tmp); 633b2167459SRichard Henderson break; 634b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 635b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 636b2167459SRichard Henderson break; 637b2167459SRichard Henderson case 7: /* OD / EV */ 638b2167459SRichard Henderson tmp = tcg_temp_new(); 639b2167459SRichard Henderson tcg_gen_andi_tl(tmp, res, 1); 640b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 641b2167459SRichard Henderson tcg_temp_free(tmp); 642b2167459SRichard Henderson break; 643b2167459SRichard Henderson default: 644b2167459SRichard Henderson g_assert_not_reached(); 645b2167459SRichard Henderson } 646b2167459SRichard Henderson if (cf & 1) { 647b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 648b2167459SRichard Henderson } 649b2167459SRichard Henderson 650b2167459SRichard Henderson return cond; 651b2167459SRichard Henderson } 652b2167459SRichard Henderson 653b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 654b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 655b2167459SRichard Henderson deleted as unused. */ 656b2167459SRichard Henderson 657b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv) 658b2167459SRichard Henderson { 659b2167459SRichard Henderson DisasCond cond; 660b2167459SRichard Henderson 661b2167459SRichard Henderson switch (cf >> 1) { 662b2167459SRichard Henderson case 1: /* = / <> */ 663b2167459SRichard Henderson cond = cond_make(TCG_COND_EQ, in1, in2); 664b2167459SRichard Henderson break; 665b2167459SRichard Henderson case 2: /* < / >= */ 666b2167459SRichard Henderson cond = cond_make(TCG_COND_LT, in1, in2); 667b2167459SRichard Henderson break; 668b2167459SRichard Henderson case 3: /* <= / > */ 669b2167459SRichard Henderson cond = cond_make(TCG_COND_LE, in1, in2); 670b2167459SRichard Henderson break; 671b2167459SRichard Henderson case 4: /* << / >>= */ 672b2167459SRichard Henderson cond = cond_make(TCG_COND_LTU, in1, in2); 673b2167459SRichard Henderson break; 674b2167459SRichard Henderson case 5: /* <<= / >> */ 675b2167459SRichard Henderson cond = cond_make(TCG_COND_LEU, in1, in2); 676b2167459SRichard Henderson break; 677b2167459SRichard Henderson default: 678b2167459SRichard Henderson return do_cond(cf, res, sv, sv); 679b2167459SRichard Henderson } 680b2167459SRichard Henderson if (cf & 1) { 681b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 682b2167459SRichard Henderson } 683b2167459SRichard Henderson 684b2167459SRichard Henderson return cond; 685b2167459SRichard Henderson } 686b2167459SRichard Henderson 687b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not 688b2167459SRichard Henderson computed, and use of them is undefined. */ 689b2167459SRichard Henderson 690b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res) 691b2167459SRichard Henderson { 692b2167459SRichard Henderson switch (cf >> 1) { 693b2167459SRichard Henderson case 4: case 5: case 6: 694b2167459SRichard Henderson cf &= 1; 695b2167459SRichard Henderson break; 696b2167459SRichard Henderson } 697b2167459SRichard Henderson return do_cond(cf, res, res, res); 698b2167459SRichard Henderson } 699b2167459SRichard Henderson 70098cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 70198cd9ca7SRichard Henderson 70298cd9ca7SRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv res) 70398cd9ca7SRichard Henderson { 70498cd9ca7SRichard Henderson unsigned c, f; 70598cd9ca7SRichard Henderson 70698cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 70798cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 70898cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 70998cd9ca7SRichard Henderson c = orig & 3; 71098cd9ca7SRichard Henderson if (c == 3) { 71198cd9ca7SRichard Henderson c = 7; 71298cd9ca7SRichard Henderson } 71398cd9ca7SRichard Henderson f = (orig & 4) / 4; 71498cd9ca7SRichard Henderson 71598cd9ca7SRichard Henderson return do_log_cond(c * 2 + f, res); 71698cd9ca7SRichard Henderson } 71798cd9ca7SRichard Henderson 718b2167459SRichard Henderson /* Similar, but for unit conditions. */ 719b2167459SRichard Henderson 720b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2) 721b2167459SRichard Henderson { 722b2167459SRichard Henderson DisasCond cond; 723b2167459SRichard Henderson TCGv tmp, cb; 724b2167459SRichard Henderson 725b2167459SRichard Henderson TCGV_UNUSED(cb); 726b2167459SRichard Henderson if (cf & 8) { 727b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 728b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 729b2167459SRichard Henderson * leaves us with carry bits spread across two words. 730b2167459SRichard Henderson */ 731b2167459SRichard Henderson cb = tcg_temp_new(); 732b2167459SRichard Henderson tmp = tcg_temp_new(); 733b2167459SRichard Henderson tcg_gen_or_tl(cb, in1, in2); 734b2167459SRichard Henderson tcg_gen_and_tl(tmp, in1, in2); 735b2167459SRichard Henderson tcg_gen_andc_tl(cb, cb, res); 736b2167459SRichard Henderson tcg_gen_or_tl(cb, cb, tmp); 737b2167459SRichard Henderson tcg_temp_free(tmp); 738b2167459SRichard Henderson } 739b2167459SRichard Henderson 740b2167459SRichard Henderson switch (cf >> 1) { 741b2167459SRichard Henderson case 0: /* never / TR */ 742b2167459SRichard Henderson case 1: /* undefined */ 743b2167459SRichard Henderson case 5: /* undefined */ 744b2167459SRichard Henderson cond = cond_make_f(); 745b2167459SRichard Henderson break; 746b2167459SRichard Henderson 747b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 748b2167459SRichard Henderson /* See hasless(v,1) from 749b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 750b2167459SRichard Henderson */ 751b2167459SRichard Henderson tmp = tcg_temp_new(); 752b2167459SRichard Henderson tcg_gen_subi_tl(tmp, res, 0x01010101u); 753b2167459SRichard Henderson tcg_gen_andc_tl(tmp, tmp, res); 754b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x80808080u); 755b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 756b2167459SRichard Henderson tcg_temp_free(tmp); 757b2167459SRichard Henderson break; 758b2167459SRichard Henderson 759b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 760b2167459SRichard Henderson tmp = tcg_temp_new(); 761b2167459SRichard Henderson tcg_gen_subi_tl(tmp, res, 0x00010001u); 762b2167459SRichard Henderson tcg_gen_andc_tl(tmp, tmp, res); 763b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x80008000u); 764b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 765b2167459SRichard Henderson tcg_temp_free(tmp); 766b2167459SRichard Henderson break; 767b2167459SRichard Henderson 768b2167459SRichard Henderson case 4: /* SDC / NDC */ 769b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x88888888u); 770b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 771b2167459SRichard Henderson break; 772b2167459SRichard Henderson 773b2167459SRichard Henderson case 6: /* SBC / NBC */ 774b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x80808080u); 775b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 776b2167459SRichard Henderson break; 777b2167459SRichard Henderson 778b2167459SRichard Henderson case 7: /* SHC / NHC */ 779b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x80008000u); 780b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 781b2167459SRichard Henderson break; 782b2167459SRichard Henderson 783b2167459SRichard Henderson default: 784b2167459SRichard Henderson g_assert_not_reached(); 785b2167459SRichard Henderson } 786b2167459SRichard Henderson if (cf & 8) { 787b2167459SRichard Henderson tcg_temp_free(cb); 788b2167459SRichard Henderson } 789b2167459SRichard Henderson if (cf & 1) { 790b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 791b2167459SRichard Henderson } 792b2167459SRichard Henderson 793b2167459SRichard Henderson return cond; 794b2167459SRichard Henderson } 795b2167459SRichard Henderson 796b2167459SRichard Henderson /* Compute signed overflow for addition. */ 797b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2) 798b2167459SRichard Henderson { 799b2167459SRichard Henderson TCGv sv = get_temp(ctx); 800b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 801b2167459SRichard Henderson 802b2167459SRichard Henderson tcg_gen_xor_tl(sv, res, in1); 803b2167459SRichard Henderson tcg_gen_xor_tl(tmp, in1, in2); 804b2167459SRichard Henderson tcg_gen_andc_tl(sv, sv, tmp); 805b2167459SRichard Henderson tcg_temp_free(tmp); 806b2167459SRichard Henderson 807b2167459SRichard Henderson return sv; 808b2167459SRichard Henderson } 809b2167459SRichard Henderson 810b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 811b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2) 812b2167459SRichard Henderson { 813b2167459SRichard Henderson TCGv sv = get_temp(ctx); 814b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 815b2167459SRichard Henderson 816b2167459SRichard Henderson tcg_gen_xor_tl(sv, res, in1); 817b2167459SRichard Henderson tcg_gen_xor_tl(tmp, in1, in2); 818b2167459SRichard Henderson tcg_gen_and_tl(sv, sv, tmp); 819b2167459SRichard Henderson tcg_temp_free(tmp); 820b2167459SRichard Henderson 821b2167459SRichard Henderson return sv; 822b2167459SRichard Henderson } 823b2167459SRichard Henderson 824869051eaSRichard Henderson static DisasJumpType do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 825b2167459SRichard Henderson unsigned shift, bool is_l, bool is_tsv, bool is_tc, 826b2167459SRichard Henderson bool is_c, unsigned cf) 827b2167459SRichard Henderson { 828b2167459SRichard Henderson TCGv dest, cb, cb_msb, sv, tmp; 829b2167459SRichard Henderson unsigned c = cf >> 1; 830b2167459SRichard Henderson DisasCond cond; 831b2167459SRichard Henderson 832b2167459SRichard Henderson dest = tcg_temp_new(); 833b2167459SRichard Henderson TCGV_UNUSED(cb); 834b2167459SRichard Henderson TCGV_UNUSED(cb_msb); 835b2167459SRichard Henderson 836b2167459SRichard Henderson if (shift) { 837b2167459SRichard Henderson tmp = get_temp(ctx); 838b2167459SRichard Henderson tcg_gen_shli_tl(tmp, in1, shift); 839b2167459SRichard Henderson in1 = tmp; 840b2167459SRichard Henderson } 841b2167459SRichard Henderson 842b2167459SRichard Henderson if (!is_l || c == 4 || c == 5) { 843b2167459SRichard Henderson TCGv zero = tcg_const_tl(0); 844b2167459SRichard Henderson cb_msb = get_temp(ctx); 845b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero); 846b2167459SRichard Henderson if (is_c) { 847b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero); 848b2167459SRichard Henderson } 849b2167459SRichard Henderson tcg_temp_free(zero); 850b2167459SRichard Henderson if (!is_l) { 851b2167459SRichard Henderson cb = get_temp(ctx); 852b2167459SRichard Henderson tcg_gen_xor_tl(cb, in1, in2); 853b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 854b2167459SRichard Henderson } 855b2167459SRichard Henderson } else { 856b2167459SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 857b2167459SRichard Henderson if (is_c) { 858b2167459SRichard Henderson tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb); 859b2167459SRichard Henderson } 860b2167459SRichard Henderson } 861b2167459SRichard Henderson 862b2167459SRichard Henderson /* Compute signed overflow if required. */ 863b2167459SRichard Henderson TCGV_UNUSED(sv); 864b2167459SRichard Henderson if (is_tsv || c == 6) { 865b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 866b2167459SRichard Henderson if (is_tsv) { 867b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 868b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 869b2167459SRichard Henderson } 870b2167459SRichard Henderson } 871b2167459SRichard Henderson 872b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 873b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 874b2167459SRichard Henderson if (is_tc) { 875b2167459SRichard Henderson cond_prep(&cond); 876b2167459SRichard Henderson tmp = tcg_temp_new(); 877b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 878b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 879b2167459SRichard Henderson tcg_temp_free(tmp); 880b2167459SRichard Henderson } 881b2167459SRichard Henderson 882b2167459SRichard Henderson /* Write back the result. */ 883b2167459SRichard Henderson if (!is_l) { 884b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 885b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 886b2167459SRichard Henderson } 887b2167459SRichard Henderson save_gpr(ctx, rt, dest); 888b2167459SRichard Henderson tcg_temp_free(dest); 889b2167459SRichard Henderson 890b2167459SRichard Henderson /* Install the new nullification. */ 891b2167459SRichard Henderson cond_free(&ctx->null_cond); 892b2167459SRichard Henderson ctx->null_cond = cond; 893869051eaSRichard Henderson return DISAS_NEXT; 894b2167459SRichard Henderson } 895b2167459SRichard Henderson 896869051eaSRichard Henderson static DisasJumpType do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 897b2167459SRichard Henderson bool is_tsv, bool is_b, bool is_tc, unsigned cf) 898b2167459SRichard Henderson { 899b2167459SRichard Henderson TCGv dest, sv, cb, cb_msb, zero, tmp; 900b2167459SRichard Henderson unsigned c = cf >> 1; 901b2167459SRichard Henderson DisasCond cond; 902b2167459SRichard Henderson 903b2167459SRichard Henderson dest = tcg_temp_new(); 904b2167459SRichard Henderson cb = tcg_temp_new(); 905b2167459SRichard Henderson cb_msb = tcg_temp_new(); 906b2167459SRichard Henderson 907b2167459SRichard Henderson zero = tcg_const_tl(0); 908b2167459SRichard Henderson if (is_b) { 909b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 910b2167459SRichard Henderson tcg_gen_not_tl(cb, in2); 911b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero); 912b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero); 913b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, in1); 914b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 915b2167459SRichard Henderson } else { 916b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 917b2167459SRichard Henderson operations by seeding the high word with 1 and subtracting. */ 918b2167459SRichard Henderson tcg_gen_movi_tl(cb_msb, 1); 919b2167459SRichard Henderson tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero); 920b2167459SRichard Henderson tcg_gen_eqv_tl(cb, in1, in2); 921b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 922b2167459SRichard Henderson } 923b2167459SRichard Henderson tcg_temp_free(zero); 924b2167459SRichard Henderson 925b2167459SRichard Henderson /* Compute signed overflow if required. */ 926b2167459SRichard Henderson TCGV_UNUSED(sv); 927b2167459SRichard Henderson if (is_tsv || c == 6) { 928b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 929b2167459SRichard Henderson if (is_tsv) { 930b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 931b2167459SRichard Henderson } 932b2167459SRichard Henderson } 933b2167459SRichard Henderson 934b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 935b2167459SRichard Henderson if (!is_b) { 936b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 937b2167459SRichard Henderson } else { 938b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 939b2167459SRichard Henderson } 940b2167459SRichard Henderson 941b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 942b2167459SRichard Henderson if (is_tc) { 943b2167459SRichard Henderson cond_prep(&cond); 944b2167459SRichard Henderson tmp = tcg_temp_new(); 945b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 946b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 947b2167459SRichard Henderson tcg_temp_free(tmp); 948b2167459SRichard Henderson } 949b2167459SRichard Henderson 950b2167459SRichard Henderson /* Write back the result. */ 951b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 952b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 953b2167459SRichard Henderson save_gpr(ctx, rt, dest); 954b2167459SRichard Henderson tcg_temp_free(dest); 955b2167459SRichard Henderson 956b2167459SRichard Henderson /* Install the new nullification. */ 957b2167459SRichard Henderson cond_free(&ctx->null_cond); 958b2167459SRichard Henderson ctx->null_cond = cond; 959869051eaSRichard Henderson return DISAS_NEXT; 960b2167459SRichard Henderson } 961b2167459SRichard Henderson 962869051eaSRichard Henderson static DisasJumpType do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1, 963b2167459SRichard Henderson TCGv in2, unsigned cf) 964b2167459SRichard Henderson { 965b2167459SRichard Henderson TCGv dest, sv; 966b2167459SRichard Henderson DisasCond cond; 967b2167459SRichard Henderson 968b2167459SRichard Henderson dest = tcg_temp_new(); 969b2167459SRichard Henderson tcg_gen_sub_tl(dest, in1, in2); 970b2167459SRichard Henderson 971b2167459SRichard Henderson /* Compute signed overflow if required. */ 972b2167459SRichard Henderson TCGV_UNUSED(sv); 973b2167459SRichard Henderson if ((cf >> 1) == 6) { 974b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 975b2167459SRichard Henderson } 976b2167459SRichard Henderson 977b2167459SRichard Henderson /* Form the condition for the compare. */ 978b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 979b2167459SRichard Henderson 980b2167459SRichard Henderson /* Clear. */ 981b2167459SRichard Henderson tcg_gen_movi_tl(dest, 0); 982b2167459SRichard Henderson save_gpr(ctx, rt, dest); 983b2167459SRichard Henderson tcg_temp_free(dest); 984b2167459SRichard Henderson 985b2167459SRichard Henderson /* Install the new nullification. */ 986b2167459SRichard Henderson cond_free(&ctx->null_cond); 987b2167459SRichard Henderson ctx->null_cond = cond; 988869051eaSRichard Henderson return DISAS_NEXT; 989b2167459SRichard Henderson } 990b2167459SRichard Henderson 991869051eaSRichard Henderson static DisasJumpType do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 992b2167459SRichard Henderson unsigned cf, void (*fn)(TCGv, TCGv, TCGv)) 993b2167459SRichard Henderson { 994b2167459SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 995b2167459SRichard Henderson 996b2167459SRichard Henderson /* Perform the operation, and writeback. */ 997b2167459SRichard Henderson fn(dest, in1, in2); 998b2167459SRichard Henderson save_gpr(ctx, rt, dest); 999b2167459SRichard Henderson 1000b2167459SRichard Henderson /* Install the new nullification. */ 1001b2167459SRichard Henderson cond_free(&ctx->null_cond); 1002b2167459SRichard Henderson if (cf) { 1003b2167459SRichard Henderson ctx->null_cond = do_log_cond(cf, dest); 1004b2167459SRichard Henderson } 1005869051eaSRichard Henderson return DISAS_NEXT; 1006b2167459SRichard Henderson } 1007b2167459SRichard Henderson 1008869051eaSRichard Henderson static DisasJumpType do_unit(DisasContext *ctx, unsigned rt, TCGv in1, 1009b2167459SRichard Henderson TCGv in2, unsigned cf, bool is_tc, 1010b2167459SRichard Henderson void (*fn)(TCGv, TCGv, TCGv)) 1011b2167459SRichard Henderson { 1012b2167459SRichard Henderson TCGv dest; 1013b2167459SRichard Henderson DisasCond cond; 1014b2167459SRichard Henderson 1015b2167459SRichard Henderson if (cf == 0) { 1016b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 1017b2167459SRichard Henderson fn(dest, in1, in2); 1018b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1019b2167459SRichard Henderson cond_free(&ctx->null_cond); 1020b2167459SRichard Henderson } else { 1021b2167459SRichard Henderson dest = tcg_temp_new(); 1022b2167459SRichard Henderson fn(dest, in1, in2); 1023b2167459SRichard Henderson 1024b2167459SRichard Henderson cond = do_unit_cond(cf, dest, in1, in2); 1025b2167459SRichard Henderson 1026b2167459SRichard Henderson if (is_tc) { 1027b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 1028b2167459SRichard Henderson cond_prep(&cond); 1029b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 1030b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 1031b2167459SRichard Henderson tcg_temp_free(tmp); 1032b2167459SRichard Henderson } 1033b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1034b2167459SRichard Henderson 1035b2167459SRichard Henderson cond_free(&ctx->null_cond); 1036b2167459SRichard Henderson ctx->null_cond = cond; 1037b2167459SRichard Henderson } 1038869051eaSRichard Henderson return DISAS_NEXT; 1039b2167459SRichard Henderson } 1040b2167459SRichard Henderson 104196d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 104296d6407fSRichard Henderson * < 0 for pre-modify, 104396d6407fSRichard Henderson * > 0 for post-modify, 104496d6407fSRichard Henderson * = 0 for no base register update. 104596d6407fSRichard Henderson */ 104696d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 104796d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 104896d6407fSRichard Henderson int modify, TCGMemOp mop) 104996d6407fSRichard Henderson { 105096d6407fSRichard Henderson TCGv addr, base; 105196d6407fSRichard Henderson 105296d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 105396d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 105496d6407fSRichard Henderson 105596d6407fSRichard Henderson addr = tcg_temp_new(); 105696d6407fSRichard Henderson base = load_gpr(ctx, rb); 105796d6407fSRichard Henderson 105896d6407fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 105996d6407fSRichard Henderson if (rx) { 106096d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 106196d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 106296d6407fSRichard Henderson } else { 106396d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 106496d6407fSRichard Henderson } 106596d6407fSRichard Henderson 106696d6407fSRichard Henderson if (modify == 0) { 106796d6407fSRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop); 106896d6407fSRichard Henderson } else { 106996d6407fSRichard Henderson tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base), 107096d6407fSRichard Henderson MMU_USER_IDX, mop); 107196d6407fSRichard Henderson save_gpr(ctx, rb, addr); 107296d6407fSRichard Henderson } 107396d6407fSRichard Henderson tcg_temp_free(addr); 107496d6407fSRichard Henderson } 107596d6407fSRichard Henderson 107696d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 107796d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 107896d6407fSRichard Henderson int modify, TCGMemOp mop) 107996d6407fSRichard Henderson { 108096d6407fSRichard Henderson TCGv addr, base; 108196d6407fSRichard Henderson 108296d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 108396d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 108496d6407fSRichard Henderson 108596d6407fSRichard Henderson addr = tcg_temp_new(); 108696d6407fSRichard Henderson base = load_gpr(ctx, rb); 108796d6407fSRichard Henderson 108896d6407fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 108996d6407fSRichard Henderson if (rx) { 109096d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 109196d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 109296d6407fSRichard Henderson } else { 109396d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 109496d6407fSRichard Henderson } 109596d6407fSRichard Henderson 109696d6407fSRichard Henderson if (modify == 0) { 109796d6407fSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop); 109896d6407fSRichard Henderson } else { 109996d6407fSRichard Henderson tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base), 110096d6407fSRichard Henderson MMU_USER_IDX, mop); 110196d6407fSRichard Henderson save_gpr(ctx, rb, addr); 110296d6407fSRichard Henderson } 110396d6407fSRichard Henderson tcg_temp_free(addr); 110496d6407fSRichard Henderson } 110596d6407fSRichard Henderson 110696d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 110796d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 110896d6407fSRichard Henderson int modify, TCGMemOp mop) 110996d6407fSRichard Henderson { 111096d6407fSRichard Henderson TCGv addr, base; 111196d6407fSRichard Henderson 111296d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 111396d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 111496d6407fSRichard Henderson 111596d6407fSRichard Henderson addr = tcg_temp_new(); 111696d6407fSRichard Henderson base = load_gpr(ctx, rb); 111796d6407fSRichard Henderson 111896d6407fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 111996d6407fSRichard Henderson if (rx) { 112096d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 112196d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 112296d6407fSRichard Henderson } else { 112396d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 112496d6407fSRichard Henderson } 112596d6407fSRichard Henderson 112696d6407fSRichard Henderson tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop); 112796d6407fSRichard Henderson 112896d6407fSRichard Henderson if (modify != 0) { 112996d6407fSRichard Henderson save_gpr(ctx, rb, addr); 113096d6407fSRichard Henderson } 113196d6407fSRichard Henderson tcg_temp_free(addr); 113296d6407fSRichard Henderson } 113396d6407fSRichard Henderson 113496d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 113596d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 113696d6407fSRichard Henderson int modify, TCGMemOp mop) 113796d6407fSRichard Henderson { 113896d6407fSRichard Henderson TCGv addr, base; 113996d6407fSRichard Henderson 114096d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 114196d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 114296d6407fSRichard Henderson 114396d6407fSRichard Henderson addr = tcg_temp_new(); 114496d6407fSRichard Henderson base = load_gpr(ctx, rb); 114596d6407fSRichard Henderson 114696d6407fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 114796d6407fSRichard Henderson if (rx) { 114896d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 114996d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 115096d6407fSRichard Henderson } else { 115196d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 115296d6407fSRichard Henderson } 115396d6407fSRichard Henderson 115496d6407fSRichard Henderson tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop); 115596d6407fSRichard Henderson 115696d6407fSRichard Henderson if (modify != 0) { 115796d6407fSRichard Henderson save_gpr(ctx, rb, addr); 115896d6407fSRichard Henderson } 115996d6407fSRichard Henderson tcg_temp_free(addr); 116096d6407fSRichard Henderson } 116196d6407fSRichard Henderson 116296d6407fSRichard Henderson #if TARGET_LONG_BITS == 64 116396d6407fSRichard Henderson #define do_load_tl do_load_64 116496d6407fSRichard Henderson #define do_store_tl do_store_64 116596d6407fSRichard Henderson #else 116696d6407fSRichard Henderson #define do_load_tl do_load_32 116796d6407fSRichard Henderson #define do_store_tl do_store_32 116896d6407fSRichard Henderson #endif 116996d6407fSRichard Henderson 1170869051eaSRichard Henderson static DisasJumpType do_load(DisasContext *ctx, unsigned rt, unsigned rb, 117196d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 117296d6407fSRichard Henderson int modify, TCGMemOp mop) 117396d6407fSRichard Henderson { 117496d6407fSRichard Henderson TCGv dest; 117596d6407fSRichard Henderson 117696d6407fSRichard Henderson nullify_over(ctx); 117796d6407fSRichard Henderson 117896d6407fSRichard Henderson if (modify == 0) { 117996d6407fSRichard Henderson /* No base register update. */ 118096d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 118196d6407fSRichard Henderson } else { 118296d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 118396d6407fSRichard Henderson dest = get_temp(ctx); 118496d6407fSRichard Henderson } 118596d6407fSRichard Henderson do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop); 118696d6407fSRichard Henderson save_gpr(ctx, rt, dest); 118796d6407fSRichard Henderson 1188869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 118996d6407fSRichard Henderson } 119096d6407fSRichard Henderson 1191869051eaSRichard Henderson static DisasJumpType do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 119296d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 119396d6407fSRichard Henderson int modify) 119496d6407fSRichard Henderson { 119596d6407fSRichard Henderson TCGv_i32 tmp; 119696d6407fSRichard Henderson 119796d6407fSRichard Henderson nullify_over(ctx); 119896d6407fSRichard Henderson 119996d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 120096d6407fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL); 120196d6407fSRichard Henderson save_frw_i32(rt, tmp); 120296d6407fSRichard Henderson tcg_temp_free_i32(tmp); 120396d6407fSRichard Henderson 120496d6407fSRichard Henderson if (rt == 0) { 120596d6407fSRichard Henderson gen_helper_loaded_fr0(cpu_env); 120696d6407fSRichard Henderson } 120796d6407fSRichard Henderson 1208869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 120996d6407fSRichard Henderson } 121096d6407fSRichard Henderson 1211869051eaSRichard Henderson static DisasJumpType do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 121296d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 121396d6407fSRichard Henderson int modify) 121496d6407fSRichard Henderson { 121596d6407fSRichard Henderson TCGv_i64 tmp; 121696d6407fSRichard Henderson 121796d6407fSRichard Henderson nullify_over(ctx); 121896d6407fSRichard Henderson 121996d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 122096d6407fSRichard Henderson do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ); 122196d6407fSRichard Henderson save_frd(rt, tmp); 122296d6407fSRichard Henderson tcg_temp_free_i64(tmp); 122396d6407fSRichard Henderson 122496d6407fSRichard Henderson if (rt == 0) { 122596d6407fSRichard Henderson gen_helper_loaded_fr0(cpu_env); 122696d6407fSRichard Henderson } 122796d6407fSRichard Henderson 1228869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 122996d6407fSRichard Henderson } 123096d6407fSRichard Henderson 1231869051eaSRichard Henderson static DisasJumpType do_store(DisasContext *ctx, unsigned rt, unsigned rb, 123296d6407fSRichard Henderson target_long disp, int modify, TCGMemOp mop) 123396d6407fSRichard Henderson { 123496d6407fSRichard Henderson nullify_over(ctx); 123596d6407fSRichard Henderson do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop); 1236869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 123796d6407fSRichard Henderson } 123896d6407fSRichard Henderson 1239869051eaSRichard Henderson static DisasJumpType do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 124096d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 124196d6407fSRichard Henderson int modify) 124296d6407fSRichard Henderson { 124396d6407fSRichard Henderson TCGv_i32 tmp; 124496d6407fSRichard Henderson 124596d6407fSRichard Henderson nullify_over(ctx); 124696d6407fSRichard Henderson 124796d6407fSRichard Henderson tmp = load_frw_i32(rt); 124896d6407fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL); 124996d6407fSRichard Henderson tcg_temp_free_i32(tmp); 125096d6407fSRichard Henderson 1251869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 125296d6407fSRichard Henderson } 125396d6407fSRichard Henderson 1254869051eaSRichard Henderson static DisasJumpType do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 125596d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 125696d6407fSRichard Henderson int modify) 125796d6407fSRichard Henderson { 125896d6407fSRichard Henderson TCGv_i64 tmp; 125996d6407fSRichard Henderson 126096d6407fSRichard Henderson nullify_over(ctx); 126196d6407fSRichard Henderson 126296d6407fSRichard Henderson tmp = load_frd(rt); 126396d6407fSRichard Henderson do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ); 126496d6407fSRichard Henderson tcg_temp_free_i64(tmp); 126596d6407fSRichard Henderson 1266869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 126796d6407fSRichard Henderson } 126896d6407fSRichard Henderson 1269869051eaSRichard Henderson static DisasJumpType do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1270ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1271ebe9383cSRichard Henderson { 1272ebe9383cSRichard Henderson TCGv_i32 tmp; 1273ebe9383cSRichard Henderson 1274ebe9383cSRichard Henderson nullify_over(ctx); 1275ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1276ebe9383cSRichard Henderson 1277ebe9383cSRichard Henderson func(tmp, cpu_env, tmp); 1278ebe9383cSRichard Henderson 1279ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 1280ebe9383cSRichard Henderson tcg_temp_free_i32(tmp); 1281869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 1282ebe9383cSRichard Henderson } 1283ebe9383cSRichard Henderson 1284869051eaSRichard Henderson static DisasJumpType do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1285ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1286ebe9383cSRichard Henderson { 1287ebe9383cSRichard Henderson TCGv_i32 dst; 1288ebe9383cSRichard Henderson TCGv_i64 src; 1289ebe9383cSRichard Henderson 1290ebe9383cSRichard Henderson nullify_over(ctx); 1291ebe9383cSRichard Henderson src = load_frd(ra); 1292ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1293ebe9383cSRichard Henderson 1294ebe9383cSRichard Henderson func(dst, cpu_env, src); 1295ebe9383cSRichard Henderson 1296ebe9383cSRichard Henderson tcg_temp_free_i64(src); 1297ebe9383cSRichard Henderson save_frw_i32(rt, dst); 1298ebe9383cSRichard Henderson tcg_temp_free_i32(dst); 1299869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 1300ebe9383cSRichard Henderson } 1301ebe9383cSRichard Henderson 1302869051eaSRichard Henderson static DisasJumpType do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1303ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1304ebe9383cSRichard Henderson { 1305ebe9383cSRichard Henderson TCGv_i64 tmp; 1306ebe9383cSRichard Henderson 1307ebe9383cSRichard Henderson nullify_over(ctx); 1308ebe9383cSRichard Henderson tmp = load_frd0(ra); 1309ebe9383cSRichard Henderson 1310ebe9383cSRichard Henderson func(tmp, cpu_env, tmp); 1311ebe9383cSRichard Henderson 1312ebe9383cSRichard Henderson save_frd(rt, tmp); 1313ebe9383cSRichard Henderson tcg_temp_free_i64(tmp); 1314869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 1315ebe9383cSRichard Henderson } 1316ebe9383cSRichard Henderson 1317869051eaSRichard Henderson static DisasJumpType do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1318ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1319ebe9383cSRichard Henderson { 1320ebe9383cSRichard Henderson TCGv_i32 src; 1321ebe9383cSRichard Henderson TCGv_i64 dst; 1322ebe9383cSRichard Henderson 1323ebe9383cSRichard Henderson nullify_over(ctx); 1324ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1325ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1326ebe9383cSRichard Henderson 1327ebe9383cSRichard Henderson func(dst, cpu_env, src); 1328ebe9383cSRichard Henderson 1329ebe9383cSRichard Henderson tcg_temp_free_i32(src); 1330ebe9383cSRichard Henderson save_frd(rt, dst); 1331ebe9383cSRichard Henderson tcg_temp_free_i64(dst); 1332869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 1333ebe9383cSRichard Henderson } 1334ebe9383cSRichard Henderson 1335869051eaSRichard Henderson static DisasJumpType do_fop_weww(DisasContext *ctx, unsigned rt, 1336ebe9383cSRichard Henderson unsigned ra, unsigned rb, 1337ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, 1338ebe9383cSRichard Henderson TCGv_i32, TCGv_i32)) 1339ebe9383cSRichard Henderson { 1340ebe9383cSRichard Henderson TCGv_i32 a, b; 1341ebe9383cSRichard Henderson 1342ebe9383cSRichard Henderson nullify_over(ctx); 1343ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1344ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1345ebe9383cSRichard Henderson 1346ebe9383cSRichard Henderson func(a, cpu_env, a, b); 1347ebe9383cSRichard Henderson 1348ebe9383cSRichard Henderson tcg_temp_free_i32(b); 1349ebe9383cSRichard Henderson save_frw_i32(rt, a); 1350ebe9383cSRichard Henderson tcg_temp_free_i32(a); 1351869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 1352ebe9383cSRichard Henderson } 1353ebe9383cSRichard Henderson 1354869051eaSRichard Henderson static DisasJumpType do_fop_dedd(DisasContext *ctx, unsigned rt, 1355ebe9383cSRichard Henderson unsigned ra, unsigned rb, 1356ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, 1357ebe9383cSRichard Henderson TCGv_i64, TCGv_i64)) 1358ebe9383cSRichard Henderson { 1359ebe9383cSRichard Henderson TCGv_i64 a, b; 1360ebe9383cSRichard Henderson 1361ebe9383cSRichard Henderson nullify_over(ctx); 1362ebe9383cSRichard Henderson a = load_frd0(ra); 1363ebe9383cSRichard Henderson b = load_frd0(rb); 1364ebe9383cSRichard Henderson 1365ebe9383cSRichard Henderson func(a, cpu_env, a, b); 1366ebe9383cSRichard Henderson 1367ebe9383cSRichard Henderson tcg_temp_free_i64(b); 1368ebe9383cSRichard Henderson save_frd(rt, a); 1369ebe9383cSRichard Henderson tcg_temp_free_i64(a); 1370869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 1371ebe9383cSRichard Henderson } 1372ebe9383cSRichard Henderson 137398cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 137498cd9ca7SRichard Henderson have already had nullification handled. */ 1375869051eaSRichard Henderson static DisasJumpType do_dbranch(DisasContext *ctx, target_ulong dest, 137698cd9ca7SRichard Henderson unsigned link, bool is_n) 137798cd9ca7SRichard Henderson { 137898cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 137998cd9ca7SRichard Henderson if (link != 0) { 138098cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 138198cd9ca7SRichard Henderson } 138298cd9ca7SRichard Henderson ctx->iaoq_n = dest; 138398cd9ca7SRichard Henderson if (is_n) { 138498cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 138598cd9ca7SRichard Henderson } 1386869051eaSRichard Henderson return DISAS_NEXT; 138798cd9ca7SRichard Henderson } else { 138898cd9ca7SRichard Henderson nullify_over(ctx); 138998cd9ca7SRichard Henderson 139098cd9ca7SRichard Henderson if (link != 0) { 139198cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 139298cd9ca7SRichard Henderson } 139398cd9ca7SRichard Henderson 139498cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 139598cd9ca7SRichard Henderson nullify_set(ctx, 0); 139698cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 139798cd9ca7SRichard Henderson } else { 139898cd9ca7SRichard Henderson nullify_set(ctx, is_n); 139998cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 140098cd9ca7SRichard Henderson } 140198cd9ca7SRichard Henderson 1402869051eaSRichard Henderson nullify_end(ctx, DISAS_NEXT); 140398cd9ca7SRichard Henderson 140498cd9ca7SRichard Henderson nullify_set(ctx, 0); 140598cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 1406869051eaSRichard Henderson return DISAS_NORETURN; 140798cd9ca7SRichard Henderson } 140898cd9ca7SRichard Henderson } 140998cd9ca7SRichard Henderson 141098cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 141198cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1412869051eaSRichard Henderson static DisasJumpType do_cbranch(DisasContext *ctx, target_long disp, bool is_n, 141398cd9ca7SRichard Henderson DisasCond *cond) 141498cd9ca7SRichard Henderson { 141598cd9ca7SRichard Henderson target_ulong dest = iaoq_dest(ctx, disp); 141698cd9ca7SRichard Henderson TCGLabel *taken = NULL; 141798cd9ca7SRichard Henderson TCGCond c = cond->c; 141898cd9ca7SRichard Henderson bool n; 141998cd9ca7SRichard Henderson 142098cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 142198cd9ca7SRichard Henderson 142298cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 142398cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 142498cd9ca7SRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 142598cd9ca7SRichard Henderson } 142698cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 142798cd9ca7SRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 142898cd9ca7SRichard Henderson } 142998cd9ca7SRichard Henderson 143098cd9ca7SRichard Henderson taken = gen_new_label(); 143198cd9ca7SRichard Henderson cond_prep(cond); 143298cd9ca7SRichard Henderson tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken); 143398cd9ca7SRichard Henderson cond_free(cond); 143498cd9ca7SRichard Henderson 143598cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 143698cd9ca7SRichard Henderson n = is_n && disp < 0; 143798cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 143898cd9ca7SRichard Henderson nullify_set(ctx, 0); 1439a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 144098cd9ca7SRichard Henderson } else { 144198cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 144298cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 144398cd9ca7SRichard Henderson ctx->null_lab = NULL; 144498cd9ca7SRichard Henderson } 144598cd9ca7SRichard Henderson nullify_set(ctx, n); 1446a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 144798cd9ca7SRichard Henderson } 144898cd9ca7SRichard Henderson 144998cd9ca7SRichard Henderson gen_set_label(taken); 145098cd9ca7SRichard Henderson 145198cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 145298cd9ca7SRichard Henderson n = is_n && disp >= 0; 145398cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 145498cd9ca7SRichard Henderson nullify_set(ctx, 0); 1455a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, dest, dest + 4); 145698cd9ca7SRichard Henderson } else { 145798cd9ca7SRichard Henderson nullify_set(ctx, n); 1458a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 145998cd9ca7SRichard Henderson } 146098cd9ca7SRichard Henderson 146198cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 146298cd9ca7SRichard Henderson if (ctx->null_lab) { 146398cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 146498cd9ca7SRichard Henderson ctx->null_lab = NULL; 1465869051eaSRichard Henderson return DISAS_IAQ_N_STALE; 146698cd9ca7SRichard Henderson } else { 1467869051eaSRichard Henderson return DISAS_NORETURN; 146898cd9ca7SRichard Henderson } 146998cd9ca7SRichard Henderson } 147098cd9ca7SRichard Henderson 147198cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 147298cd9ca7SRichard Henderson nullification of the branch itself. */ 1473869051eaSRichard Henderson static DisasJumpType do_ibranch(DisasContext *ctx, TCGv dest, 147498cd9ca7SRichard Henderson unsigned link, bool is_n) 147598cd9ca7SRichard Henderson { 147698cd9ca7SRichard Henderson TCGv a0, a1, next, tmp; 147798cd9ca7SRichard Henderson TCGCond c; 147898cd9ca7SRichard Henderson 147998cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 148098cd9ca7SRichard Henderson 148198cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 148298cd9ca7SRichard Henderson if (link != 0) { 148398cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 148498cd9ca7SRichard Henderson } 148598cd9ca7SRichard Henderson next = get_temp(ctx); 148698cd9ca7SRichard Henderson tcg_gen_mov_tl(next, dest); 148798cd9ca7SRichard Henderson ctx->iaoq_n = -1; 148898cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 148998cd9ca7SRichard Henderson if (is_n) { 149098cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 149198cd9ca7SRichard Henderson } 149298cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 149398cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 149498cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 14954137cb83SRichard Henderson tracepoint in effect). Since the goto_ptr that we must use 149698cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 149798cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 149898cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 149998cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 150098cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 150198cd9ca7SRichard Henderson 150298cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 150398cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 150498cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 150598cd9ca7SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, dest); 150698cd9ca7SRichard Henderson tcg_gen_addi_tl(cpu_iaoq_b, dest, 4); 150798cd9ca7SRichard Henderson 150898cd9ca7SRichard Henderson nullify_over(ctx); 150998cd9ca7SRichard Henderson if (link != 0) { 151098cd9ca7SRichard Henderson tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n); 151198cd9ca7SRichard Henderson } 15127f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 1513869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 151498cd9ca7SRichard Henderson } else { 151598cd9ca7SRichard Henderson cond_prep(&ctx->null_cond); 151698cd9ca7SRichard Henderson c = ctx->null_cond.c; 151798cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 151898cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 151998cd9ca7SRichard Henderson 152098cd9ca7SRichard Henderson tmp = tcg_temp_new(); 152198cd9ca7SRichard Henderson next = get_temp(ctx); 152298cd9ca7SRichard Henderson 152398cd9ca7SRichard Henderson copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var); 152498cd9ca7SRichard Henderson tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest); 152598cd9ca7SRichard Henderson ctx->iaoq_n = -1; 152698cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 152798cd9ca7SRichard Henderson 152898cd9ca7SRichard Henderson if (link != 0) { 152998cd9ca7SRichard Henderson tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 153098cd9ca7SRichard Henderson } 153198cd9ca7SRichard Henderson 153298cd9ca7SRichard Henderson if (is_n) { 153398cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 153498cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 153598cd9ca7SRichard Henderson to the branch. */ 153698cd9ca7SRichard Henderson tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1); 153798cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 153898cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 153998cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 154098cd9ca7SRichard Henderson } else { 154198cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 154298cd9ca7SRichard Henderson } 154398cd9ca7SRichard Henderson } 154498cd9ca7SRichard Henderson 1545869051eaSRichard Henderson return DISAS_NEXT; 154698cd9ca7SRichard Henderson } 154798cd9ca7SRichard Henderson 15487ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 15497ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 15507ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 15517ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 15527ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 15537ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 15547ad439dfSRichard Henderson aforementioned BE. */ 1555869051eaSRichard Henderson static DisasJumpType do_page_zero(DisasContext *ctx) 15567ad439dfSRichard Henderson { 15577ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 15587ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 15597ad439dfSRichard Henderson next insn within the privilaged page. */ 15607ad439dfSRichard Henderson switch (ctx->null_cond.c) { 15617ad439dfSRichard Henderson case TCG_COND_NEVER: 15627ad439dfSRichard Henderson break; 15637ad439dfSRichard Henderson case TCG_COND_ALWAYS: 15647ad439dfSRichard Henderson tcg_gen_movi_tl(cpu_psw_n, 0); 15657ad439dfSRichard Henderson goto do_sigill; 15667ad439dfSRichard Henderson default: 15677ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 15687ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 15697ad439dfSRichard Henderson g_assert_not_reached(); 15707ad439dfSRichard Henderson } 15717ad439dfSRichard Henderson 15727ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 15737ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 15747ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 15757ad439dfSRichard Henderson under such conditions. */ 15767ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 15777ad439dfSRichard Henderson goto do_sigill; 15787ad439dfSRichard Henderson } 15797ad439dfSRichard Henderson 15807ad439dfSRichard Henderson switch (ctx->iaoq_f) { 15817ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 15827ad439dfSRichard Henderson gen_excp_1(EXCP_SIGSEGV); 1583869051eaSRichard Henderson return DISAS_NORETURN; 15847ad439dfSRichard Henderson 15857ad439dfSRichard Henderson case 0xb0: /* LWS */ 15867ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 1587869051eaSRichard Henderson return DISAS_NORETURN; 15887ad439dfSRichard Henderson 15897ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 15907ad439dfSRichard Henderson tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]); 15917ad439dfSRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]); 15927ad439dfSRichard Henderson tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4); 1593869051eaSRichard Henderson return DISAS_IAQ_N_UPDATED; 15947ad439dfSRichard Henderson 15957ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 15967ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 1597869051eaSRichard Henderson return DISAS_NORETURN; 15987ad439dfSRichard Henderson 15997ad439dfSRichard Henderson default: 16007ad439dfSRichard Henderson do_sigill: 16017ad439dfSRichard Henderson gen_excp_1(EXCP_SIGILL); 1602869051eaSRichard Henderson return DISAS_NORETURN; 16037ad439dfSRichard Henderson } 16047ad439dfSRichard Henderson } 16057ad439dfSRichard Henderson 1606869051eaSRichard Henderson static DisasJumpType trans_nop(DisasContext *ctx, uint32_t insn, 1607b2167459SRichard Henderson const DisasInsn *di) 1608b2167459SRichard Henderson { 1609b2167459SRichard Henderson cond_free(&ctx->null_cond); 1610869051eaSRichard Henderson return DISAS_NEXT; 1611b2167459SRichard Henderson } 1612b2167459SRichard Henderson 1613869051eaSRichard Henderson static DisasJumpType trans_break(DisasContext *ctx, uint32_t insn, 161498a9cb79SRichard Henderson const DisasInsn *di) 161598a9cb79SRichard Henderson { 161698a9cb79SRichard Henderson nullify_over(ctx); 161798a9cb79SRichard Henderson return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG)); 161898a9cb79SRichard Henderson } 161998a9cb79SRichard Henderson 1620869051eaSRichard Henderson static DisasJumpType trans_sync(DisasContext *ctx, uint32_t insn, 162198a9cb79SRichard Henderson const DisasInsn *di) 162298a9cb79SRichard Henderson { 162398a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 162498a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 162598a9cb79SRichard Henderson 162698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 1627869051eaSRichard Henderson return DISAS_NEXT; 162898a9cb79SRichard Henderson } 162998a9cb79SRichard Henderson 1630869051eaSRichard Henderson static DisasJumpType trans_mfia(DisasContext *ctx, uint32_t insn, 163198a9cb79SRichard Henderson const DisasInsn *di) 163298a9cb79SRichard Henderson { 163398a9cb79SRichard Henderson unsigned rt = extract32(insn, 0, 5); 163498a9cb79SRichard Henderson TCGv tmp = dest_gpr(ctx, rt); 163598a9cb79SRichard Henderson tcg_gen_movi_tl(tmp, ctx->iaoq_f); 163698a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 163798a9cb79SRichard Henderson 163898a9cb79SRichard Henderson cond_free(&ctx->null_cond); 1639869051eaSRichard Henderson return DISAS_NEXT; 164098a9cb79SRichard Henderson } 164198a9cb79SRichard Henderson 1642869051eaSRichard Henderson static DisasJumpType trans_mfsp(DisasContext *ctx, uint32_t insn, 164398a9cb79SRichard Henderson const DisasInsn *di) 164498a9cb79SRichard Henderson { 164598a9cb79SRichard Henderson unsigned rt = extract32(insn, 0, 5); 164698a9cb79SRichard Henderson TCGv tmp = dest_gpr(ctx, rt); 164798a9cb79SRichard Henderson 164898a9cb79SRichard Henderson /* ??? We don't implement space registers. */ 164998a9cb79SRichard Henderson tcg_gen_movi_tl(tmp, 0); 165098a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 165198a9cb79SRichard Henderson 165298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 1653869051eaSRichard Henderson return DISAS_NEXT; 165498a9cb79SRichard Henderson } 165598a9cb79SRichard Henderson 1656869051eaSRichard Henderson static DisasJumpType trans_mfctl(DisasContext *ctx, uint32_t insn, 165798a9cb79SRichard Henderson const DisasInsn *di) 165898a9cb79SRichard Henderson { 165998a9cb79SRichard Henderson unsigned rt = extract32(insn, 0, 5); 166098a9cb79SRichard Henderson unsigned ctl = extract32(insn, 21, 5); 166198a9cb79SRichard Henderson TCGv tmp; 166298a9cb79SRichard Henderson 166398a9cb79SRichard Henderson switch (ctl) { 166498a9cb79SRichard Henderson case 11: /* SAR */ 166598a9cb79SRichard Henderson #ifdef TARGET_HPPA64 166698a9cb79SRichard Henderson if (extract32(insn, 14, 1) == 0) { 166798a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 166898a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 166998a9cb79SRichard Henderson tcg_gen_andi_tl(tmp, cpu_sar, 31); 167098a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 167198a9cb79SRichard Henderson break; 167298a9cb79SRichard Henderson } 167398a9cb79SRichard Henderson #endif 167498a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 167598a9cb79SRichard Henderson break; 167698a9cb79SRichard Henderson case 16: /* Interval Timer */ 167798a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 167898a9cb79SRichard Henderson tcg_gen_movi_tl(tmp, 0); /* FIXME */ 167998a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 168098a9cb79SRichard Henderson break; 168198a9cb79SRichard Henderson case 26: 168298a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_cr26); 168398a9cb79SRichard Henderson break; 168498a9cb79SRichard Henderson case 27: 168598a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_cr27); 168698a9cb79SRichard Henderson break; 168798a9cb79SRichard Henderson default: 168898a9cb79SRichard Henderson /* All other control registers are privileged. */ 168998a9cb79SRichard Henderson return gen_illegal(ctx); 169098a9cb79SRichard Henderson } 169198a9cb79SRichard Henderson 169298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 1693869051eaSRichard Henderson return DISAS_NEXT; 169498a9cb79SRichard Henderson } 169598a9cb79SRichard Henderson 1696869051eaSRichard Henderson static DisasJumpType trans_mtctl(DisasContext *ctx, uint32_t insn, 169798a9cb79SRichard Henderson const DisasInsn *di) 169898a9cb79SRichard Henderson { 169998a9cb79SRichard Henderson unsigned rin = extract32(insn, 16, 5); 170098a9cb79SRichard Henderson unsigned ctl = extract32(insn, 21, 5); 170198a9cb79SRichard Henderson TCGv tmp; 170298a9cb79SRichard Henderson 170398a9cb79SRichard Henderson if (ctl == 11) { /* SAR */ 170498a9cb79SRichard Henderson tmp = tcg_temp_new(); 170598a9cb79SRichard Henderson tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1); 170698a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 170798a9cb79SRichard Henderson tcg_temp_free(tmp); 170898a9cb79SRichard Henderson } else { 170998a9cb79SRichard Henderson /* All other control registers are privileged or read-only. */ 171098a9cb79SRichard Henderson return gen_illegal(ctx); 171198a9cb79SRichard Henderson } 171298a9cb79SRichard Henderson 171398a9cb79SRichard Henderson cond_free(&ctx->null_cond); 1714869051eaSRichard Henderson return DISAS_NEXT; 171598a9cb79SRichard Henderson } 171698a9cb79SRichard Henderson 1717869051eaSRichard Henderson static DisasJumpType trans_mtsarcm(DisasContext *ctx, uint32_t insn, 171898a9cb79SRichard Henderson const DisasInsn *di) 171998a9cb79SRichard Henderson { 172098a9cb79SRichard Henderson unsigned rin = extract32(insn, 16, 5); 172198a9cb79SRichard Henderson TCGv tmp = tcg_temp_new(); 172298a9cb79SRichard Henderson 172398a9cb79SRichard Henderson tcg_gen_not_tl(tmp, load_gpr(ctx, rin)); 172498a9cb79SRichard Henderson tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1); 172598a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 172698a9cb79SRichard Henderson tcg_temp_free(tmp); 172798a9cb79SRichard Henderson 172898a9cb79SRichard Henderson cond_free(&ctx->null_cond); 1729869051eaSRichard Henderson return DISAS_NEXT; 173098a9cb79SRichard Henderson } 173198a9cb79SRichard Henderson 1732869051eaSRichard Henderson static DisasJumpType trans_ldsid(DisasContext *ctx, uint32_t insn, 173398a9cb79SRichard Henderson const DisasInsn *di) 173498a9cb79SRichard Henderson { 173598a9cb79SRichard Henderson unsigned rt = extract32(insn, 0, 5); 173698a9cb79SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 173798a9cb79SRichard Henderson 173898a9cb79SRichard Henderson /* Since we don't implement space registers, this returns zero. */ 173998a9cb79SRichard Henderson tcg_gen_movi_tl(dest, 0); 174098a9cb79SRichard Henderson save_gpr(ctx, rt, dest); 174198a9cb79SRichard Henderson 174298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 1743869051eaSRichard Henderson return DISAS_NEXT; 174498a9cb79SRichard Henderson } 174598a9cb79SRichard Henderson 174698a9cb79SRichard Henderson static const DisasInsn table_system[] = { 174798a9cb79SRichard Henderson { 0x00000000u, 0xfc001fe0u, trans_break }, 174898a9cb79SRichard Henderson /* We don't implement space register, so MTSP is a nop. */ 174998a9cb79SRichard Henderson { 0x00001820u, 0xffe01fffu, trans_nop }, 175098a9cb79SRichard Henderson { 0x00001840u, 0xfc00ffffu, trans_mtctl }, 175198a9cb79SRichard Henderson { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm }, 175298a9cb79SRichard Henderson { 0x000014a0u, 0xffffffe0u, trans_mfia }, 175398a9cb79SRichard Henderson { 0x000004a0u, 0xffff1fe0u, trans_mfsp }, 175498a9cb79SRichard Henderson { 0x000008a0u, 0xfc1fffe0u, trans_mfctl }, 175598a9cb79SRichard Henderson { 0x00000400u, 0xffffffffu, trans_sync }, 175698a9cb79SRichard Henderson { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid }, 175798a9cb79SRichard Henderson }; 175898a9cb79SRichard Henderson 1759869051eaSRichard Henderson static DisasJumpType trans_base_idx_mod(DisasContext *ctx, uint32_t insn, 176098a9cb79SRichard Henderson const DisasInsn *di) 176198a9cb79SRichard Henderson { 176298a9cb79SRichard Henderson unsigned rb = extract32(insn, 21, 5); 176398a9cb79SRichard Henderson unsigned rx = extract32(insn, 16, 5); 176498a9cb79SRichard Henderson TCGv dest = dest_gpr(ctx, rb); 176598a9cb79SRichard Henderson TCGv src1 = load_gpr(ctx, rb); 176698a9cb79SRichard Henderson TCGv src2 = load_gpr(ctx, rx); 176798a9cb79SRichard Henderson 176898a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 176998a9cb79SRichard Henderson tcg_gen_add_tl(dest, src1, src2); 177098a9cb79SRichard Henderson save_gpr(ctx, rb, dest); 177198a9cb79SRichard Henderson 177298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 1773869051eaSRichard Henderson return DISAS_NEXT; 177498a9cb79SRichard Henderson } 177598a9cb79SRichard Henderson 1776869051eaSRichard Henderson static DisasJumpType trans_probe(DisasContext *ctx, uint32_t insn, 177798a9cb79SRichard Henderson const DisasInsn *di) 177898a9cb79SRichard Henderson { 177998a9cb79SRichard Henderson unsigned rt = extract32(insn, 0, 5); 178098a9cb79SRichard Henderson unsigned rb = extract32(insn, 21, 5); 178198a9cb79SRichard Henderson unsigned is_write = extract32(insn, 6, 1); 178298a9cb79SRichard Henderson TCGv dest; 178398a9cb79SRichard Henderson 178498a9cb79SRichard Henderson nullify_over(ctx); 178598a9cb79SRichard Henderson 178698a9cb79SRichard Henderson /* ??? Do something with priv level operand. */ 178798a9cb79SRichard Henderson dest = dest_gpr(ctx, rt); 178898a9cb79SRichard Henderson if (is_write) { 178998a9cb79SRichard Henderson gen_helper_probe_w(dest, load_gpr(ctx, rb)); 179098a9cb79SRichard Henderson } else { 179198a9cb79SRichard Henderson gen_helper_probe_r(dest, load_gpr(ctx, rb)); 179298a9cb79SRichard Henderson } 179398a9cb79SRichard Henderson save_gpr(ctx, rt, dest); 1794869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 179598a9cb79SRichard Henderson } 179698a9cb79SRichard Henderson 179798a9cb79SRichard Henderson static const DisasInsn table_mem_mgmt[] = { 179898a9cb79SRichard Henderson { 0x04003280u, 0xfc003fffu, trans_nop }, /* fdc, disp */ 179998a9cb79SRichard Henderson { 0x04001280u, 0xfc003fffu, trans_nop }, /* fdc, index */ 180098a9cb79SRichard Henderson { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */ 180198a9cb79SRichard Henderson { 0x040012c0u, 0xfc003fffu, trans_nop }, /* fdce */ 180298a9cb79SRichard Henderson { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */ 180398a9cb79SRichard Henderson { 0x04000280u, 0xfc001fffu, trans_nop }, /* fic 0a */ 180498a9cb79SRichard Henderson { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */ 180598a9cb79SRichard Henderson { 0x040013c0u, 0xfc003fffu, trans_nop }, /* fic 4f */ 180698a9cb79SRichard Henderson { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */ 180798a9cb79SRichard Henderson { 0x040002c0u, 0xfc001fffu, trans_nop }, /* fice */ 180898a9cb79SRichard Henderson { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */ 180998a9cb79SRichard Henderson { 0x04002700u, 0xfc003fffu, trans_nop }, /* pdc */ 181098a9cb79SRichard Henderson { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */ 181198a9cb79SRichard Henderson { 0x04001180u, 0xfc003fa0u, trans_probe }, /* probe */ 181298a9cb79SRichard Henderson { 0x04003180u, 0xfc003fa0u, trans_probe }, /* probei */ 181398a9cb79SRichard Henderson }; 181498a9cb79SRichard Henderson 1815869051eaSRichard Henderson static DisasJumpType trans_add(DisasContext *ctx, uint32_t insn, 1816b2167459SRichard Henderson const DisasInsn *di) 1817b2167459SRichard Henderson { 1818b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1819b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1820b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1821b2167459SRichard Henderson unsigned ext = extract32(insn, 8, 4); 1822b2167459SRichard Henderson unsigned shift = extract32(insn, 6, 2); 1823b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1824b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1825b2167459SRichard Henderson bool is_c = false; 1826b2167459SRichard Henderson bool is_l = false; 1827b2167459SRichard Henderson bool is_tc = false; 1828b2167459SRichard Henderson bool is_tsv = false; 1829869051eaSRichard Henderson DisasJumpType ret; 1830b2167459SRichard Henderson 1831b2167459SRichard Henderson switch (ext) { 1832b2167459SRichard Henderson case 0x6: /* ADD, SHLADD */ 1833b2167459SRichard Henderson break; 1834b2167459SRichard Henderson case 0xa: /* ADD,L, SHLADD,L */ 1835b2167459SRichard Henderson is_l = true; 1836b2167459SRichard Henderson break; 1837b2167459SRichard Henderson case 0xe: /* ADD,TSV, SHLADD,TSV (1) */ 1838b2167459SRichard Henderson is_tsv = true; 1839b2167459SRichard Henderson break; 1840b2167459SRichard Henderson case 0x7: /* ADD,C */ 1841b2167459SRichard Henderson is_c = true; 1842b2167459SRichard Henderson break; 1843b2167459SRichard Henderson case 0xf: /* ADD,C,TSV */ 1844b2167459SRichard Henderson is_c = is_tsv = true; 1845b2167459SRichard Henderson break; 1846b2167459SRichard Henderson default: 1847b2167459SRichard Henderson return gen_illegal(ctx); 1848b2167459SRichard Henderson } 1849b2167459SRichard Henderson 1850b2167459SRichard Henderson if (cf) { 1851b2167459SRichard Henderson nullify_over(ctx); 1852b2167459SRichard Henderson } 1853b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1854b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1855b2167459SRichard Henderson ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf); 1856b2167459SRichard Henderson return nullify_end(ctx, ret); 1857b2167459SRichard Henderson } 1858b2167459SRichard Henderson 1859869051eaSRichard Henderson static DisasJumpType trans_sub(DisasContext *ctx, uint32_t insn, 1860b2167459SRichard Henderson const DisasInsn *di) 1861b2167459SRichard Henderson { 1862b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1863b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1864b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1865b2167459SRichard Henderson unsigned ext = extract32(insn, 6, 6); 1866b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1867b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1868b2167459SRichard Henderson bool is_b = false; 1869b2167459SRichard Henderson bool is_tc = false; 1870b2167459SRichard Henderson bool is_tsv = false; 1871869051eaSRichard Henderson DisasJumpType ret; 1872b2167459SRichard Henderson 1873b2167459SRichard Henderson switch (ext) { 1874b2167459SRichard Henderson case 0x10: /* SUB */ 1875b2167459SRichard Henderson break; 1876b2167459SRichard Henderson case 0x30: /* SUB,TSV */ 1877b2167459SRichard Henderson is_tsv = true; 1878b2167459SRichard Henderson break; 1879b2167459SRichard Henderson case 0x14: /* SUB,B */ 1880b2167459SRichard Henderson is_b = true; 1881b2167459SRichard Henderson break; 1882b2167459SRichard Henderson case 0x34: /* SUB,B,TSV */ 1883b2167459SRichard Henderson is_b = is_tsv = true; 1884b2167459SRichard Henderson break; 1885b2167459SRichard Henderson case 0x13: /* SUB,TC */ 1886b2167459SRichard Henderson is_tc = true; 1887b2167459SRichard Henderson break; 1888b2167459SRichard Henderson case 0x33: /* SUB,TSV,TC */ 1889b2167459SRichard Henderson is_tc = is_tsv = true; 1890b2167459SRichard Henderson break; 1891b2167459SRichard Henderson default: 1892b2167459SRichard Henderson return gen_illegal(ctx); 1893b2167459SRichard Henderson } 1894b2167459SRichard Henderson 1895b2167459SRichard Henderson if (cf) { 1896b2167459SRichard Henderson nullify_over(ctx); 1897b2167459SRichard Henderson } 1898b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1899b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1900b2167459SRichard Henderson ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf); 1901b2167459SRichard Henderson return nullify_end(ctx, ret); 1902b2167459SRichard Henderson } 1903b2167459SRichard Henderson 1904869051eaSRichard Henderson static DisasJumpType trans_log(DisasContext *ctx, uint32_t insn, 1905b2167459SRichard Henderson const DisasInsn *di) 1906b2167459SRichard Henderson { 1907b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1908b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1909b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1910b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1911b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1912869051eaSRichard Henderson DisasJumpType ret; 1913b2167459SRichard Henderson 1914b2167459SRichard Henderson if (cf) { 1915b2167459SRichard Henderson nullify_over(ctx); 1916b2167459SRichard Henderson } 1917b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1918b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1919eff235ebSPaolo Bonzini ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f.ttt); 1920b2167459SRichard Henderson return nullify_end(ctx, ret); 1921b2167459SRichard Henderson } 1922b2167459SRichard Henderson 1923b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */ 1924869051eaSRichard Henderson static DisasJumpType trans_copy(DisasContext *ctx, uint32_t insn, 1925b2167459SRichard Henderson const DisasInsn *di) 1926b2167459SRichard Henderson { 1927b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1928b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1929b2167459SRichard Henderson 1930b2167459SRichard Henderson if (r1 == 0) { 1931b2167459SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 1932b2167459SRichard Henderson tcg_gen_movi_tl(dest, 0); 1933b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1934b2167459SRichard Henderson } else { 1935b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 1936b2167459SRichard Henderson } 1937b2167459SRichard Henderson cond_free(&ctx->null_cond); 1938869051eaSRichard Henderson return DISAS_NEXT; 1939b2167459SRichard Henderson } 1940b2167459SRichard Henderson 1941869051eaSRichard Henderson static DisasJumpType trans_cmpclr(DisasContext *ctx, uint32_t insn, 1942b2167459SRichard Henderson const DisasInsn *di) 1943b2167459SRichard Henderson { 1944b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1945b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1946b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1947b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1948b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1949869051eaSRichard Henderson DisasJumpType ret; 1950b2167459SRichard Henderson 1951b2167459SRichard Henderson if (cf) { 1952b2167459SRichard Henderson nullify_over(ctx); 1953b2167459SRichard Henderson } 1954b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1955b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1956b2167459SRichard Henderson ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf); 1957b2167459SRichard Henderson return nullify_end(ctx, ret); 1958b2167459SRichard Henderson } 1959b2167459SRichard Henderson 1960869051eaSRichard Henderson static DisasJumpType trans_uxor(DisasContext *ctx, uint32_t insn, 1961b2167459SRichard Henderson const DisasInsn *di) 1962b2167459SRichard Henderson { 1963b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1964b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1965b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1966b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1967b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1968869051eaSRichard Henderson DisasJumpType ret; 1969b2167459SRichard Henderson 1970b2167459SRichard Henderson if (cf) { 1971b2167459SRichard Henderson nullify_over(ctx); 1972b2167459SRichard Henderson } 1973b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1974b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1975b2167459SRichard Henderson ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl); 1976b2167459SRichard Henderson return nullify_end(ctx, ret); 1977b2167459SRichard Henderson } 1978b2167459SRichard Henderson 1979869051eaSRichard Henderson static DisasJumpType trans_uaddcm(DisasContext *ctx, uint32_t insn, 1980b2167459SRichard Henderson const DisasInsn *di) 1981b2167459SRichard Henderson { 1982b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1983b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1984b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1985b2167459SRichard Henderson unsigned is_tc = extract32(insn, 6, 1); 1986b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1987b2167459SRichard Henderson TCGv tcg_r1, tcg_r2, tmp; 1988869051eaSRichard Henderson DisasJumpType ret; 1989b2167459SRichard Henderson 1990b2167459SRichard Henderson if (cf) { 1991b2167459SRichard Henderson nullify_over(ctx); 1992b2167459SRichard Henderson } 1993b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1994b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1995b2167459SRichard Henderson tmp = get_temp(ctx); 1996b2167459SRichard Henderson tcg_gen_not_tl(tmp, tcg_r2); 1997b2167459SRichard Henderson ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl); 1998b2167459SRichard Henderson return nullify_end(ctx, ret); 1999b2167459SRichard Henderson } 2000b2167459SRichard Henderson 2001869051eaSRichard Henderson static DisasJumpType trans_dcor(DisasContext *ctx, uint32_t insn, 2002b2167459SRichard Henderson const DisasInsn *di) 2003b2167459SRichard Henderson { 2004b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 2005b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 2006b2167459SRichard Henderson unsigned is_i = extract32(insn, 6, 1); 2007b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 2008b2167459SRichard Henderson TCGv tmp; 2009869051eaSRichard Henderson DisasJumpType ret; 2010b2167459SRichard Henderson 2011b2167459SRichard Henderson nullify_over(ctx); 2012b2167459SRichard Henderson 2013b2167459SRichard Henderson tmp = get_temp(ctx); 2014b2167459SRichard Henderson tcg_gen_shri_tl(tmp, cpu_psw_cb, 3); 2015b2167459SRichard Henderson if (!is_i) { 2016b2167459SRichard Henderson tcg_gen_not_tl(tmp, tmp); 2017b2167459SRichard Henderson } 2018b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x11111111); 2019b2167459SRichard Henderson tcg_gen_muli_tl(tmp, tmp, 6); 2020b2167459SRichard Henderson ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false, 2021b2167459SRichard Henderson is_i ? tcg_gen_add_tl : tcg_gen_sub_tl); 2022b2167459SRichard Henderson 2023b2167459SRichard Henderson return nullify_end(ctx, ret); 2024b2167459SRichard Henderson } 2025b2167459SRichard Henderson 2026869051eaSRichard Henderson static DisasJumpType trans_ds(DisasContext *ctx, uint32_t insn, 2027b2167459SRichard Henderson const DisasInsn *di) 2028b2167459SRichard Henderson { 2029b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 2030b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 2031b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 2032b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 2033b2167459SRichard Henderson TCGv dest, add1, add2, addc, zero, in1, in2; 2034b2167459SRichard Henderson 2035b2167459SRichard Henderson nullify_over(ctx); 2036b2167459SRichard Henderson 2037b2167459SRichard Henderson in1 = load_gpr(ctx, r1); 2038b2167459SRichard Henderson in2 = load_gpr(ctx, r2); 2039b2167459SRichard Henderson 2040b2167459SRichard Henderson add1 = tcg_temp_new(); 2041b2167459SRichard Henderson add2 = tcg_temp_new(); 2042b2167459SRichard Henderson addc = tcg_temp_new(); 2043b2167459SRichard Henderson dest = tcg_temp_new(); 2044b2167459SRichard Henderson zero = tcg_const_tl(0); 2045b2167459SRichard Henderson 2046b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 2047b2167459SRichard Henderson tcg_gen_add_tl(add1, in1, in1); 2048b2167459SRichard Henderson tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb); 2049b2167459SRichard Henderson 2050b2167459SRichard Henderson /* Add or subtract R2, depending on PSW[V]. Proper computation of 2051b2167459SRichard Henderson carry{8} requires that we subtract via + ~R2 + 1, as described in 2052b2167459SRichard Henderson the manual. By extracting and masking V, we can produce the 2053b2167459SRichard Henderson proper inputs to the addition without movcond. */ 2054b2167459SRichard Henderson tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1); 2055b2167459SRichard Henderson tcg_gen_xor_tl(add2, in2, addc); 2056b2167459SRichard Henderson tcg_gen_andi_tl(addc, addc, 1); 2057b2167459SRichard Henderson /* ??? This is only correct for 32-bit. */ 2058b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero); 2059b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero); 2060b2167459SRichard Henderson 2061b2167459SRichard Henderson tcg_temp_free(addc); 2062b2167459SRichard Henderson tcg_temp_free(zero); 2063b2167459SRichard Henderson 2064b2167459SRichard Henderson /* Write back the result register. */ 2065b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2066b2167459SRichard Henderson 2067b2167459SRichard Henderson /* Write back PSW[CB]. */ 2068b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_cb, add1, add2); 2069b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest); 2070b2167459SRichard Henderson 2071b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 2072b2167459SRichard Henderson tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb); 2073b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2); 2074b2167459SRichard Henderson 2075b2167459SRichard Henderson /* Install the new nullification. */ 2076b2167459SRichard Henderson if (cf) { 2077b2167459SRichard Henderson TCGv sv; 2078b2167459SRichard Henderson TCGV_UNUSED(sv); 2079b2167459SRichard Henderson if (cf >> 1 == 6) { 2080b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 2081b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 2082b2167459SRichard Henderson } 2083b2167459SRichard Henderson ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv); 2084b2167459SRichard Henderson } 2085b2167459SRichard Henderson 2086b2167459SRichard Henderson tcg_temp_free(add1); 2087b2167459SRichard Henderson tcg_temp_free(add2); 2088b2167459SRichard Henderson tcg_temp_free(dest); 2089b2167459SRichard Henderson 2090869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 2091b2167459SRichard Henderson } 2092b2167459SRichard Henderson 2093b2167459SRichard Henderson static const DisasInsn table_arith_log[] = { 2094b2167459SRichard Henderson { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */ 2095b2167459SRichard Henderson { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */ 2096eff235ebSPaolo Bonzini { 0x08000000u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_andc_tl }, 2097eff235ebSPaolo Bonzini { 0x08000200u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_and_tl }, 2098eff235ebSPaolo Bonzini { 0x08000240u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_or_tl }, 2099eff235ebSPaolo Bonzini { 0x08000280u, 0xfc000fe0u, trans_log, .f.ttt = tcg_gen_xor_tl }, 2100b2167459SRichard Henderson { 0x08000880u, 0xfc000fe0u, trans_cmpclr }, 2101b2167459SRichard Henderson { 0x08000380u, 0xfc000fe0u, trans_uxor }, 2102b2167459SRichard Henderson { 0x08000980u, 0xfc000fa0u, trans_uaddcm }, 2103b2167459SRichard Henderson { 0x08000b80u, 0xfc1f0fa0u, trans_dcor }, 2104b2167459SRichard Henderson { 0x08000440u, 0xfc000fe0u, trans_ds }, 2105b2167459SRichard Henderson { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */ 2106b2167459SRichard Henderson { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */ 2107b2167459SRichard Henderson { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */ 2108b2167459SRichard Henderson { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */ 2109b2167459SRichard Henderson }; 2110b2167459SRichard Henderson 2111869051eaSRichard Henderson static DisasJumpType trans_addi(DisasContext *ctx, uint32_t insn) 2112b2167459SRichard Henderson { 2113b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 2114b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 2115b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 2116b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2117b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 2118b2167459SRichard Henderson unsigned o1 = extract32(insn, 26, 1); 2119b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 2120869051eaSRichard Henderson DisasJumpType ret; 2121b2167459SRichard Henderson 2122b2167459SRichard Henderson if (cf) { 2123b2167459SRichard Henderson nullify_over(ctx); 2124b2167459SRichard Henderson } 2125b2167459SRichard Henderson 2126b2167459SRichard Henderson tcg_im = load_const(ctx, im); 2127b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 2128b2167459SRichard Henderson ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf); 2129b2167459SRichard Henderson 2130b2167459SRichard Henderson return nullify_end(ctx, ret); 2131b2167459SRichard Henderson } 2132b2167459SRichard Henderson 2133869051eaSRichard Henderson static DisasJumpType trans_subi(DisasContext *ctx, uint32_t insn) 2134b2167459SRichard Henderson { 2135b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 2136b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 2137b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 2138b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2139b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 2140b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 2141869051eaSRichard Henderson DisasJumpType ret; 2142b2167459SRichard Henderson 2143b2167459SRichard Henderson if (cf) { 2144b2167459SRichard Henderson nullify_over(ctx); 2145b2167459SRichard Henderson } 2146b2167459SRichard Henderson 2147b2167459SRichard Henderson tcg_im = load_const(ctx, im); 2148b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 2149b2167459SRichard Henderson ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf); 2150b2167459SRichard Henderson 2151b2167459SRichard Henderson return nullify_end(ctx, ret); 2152b2167459SRichard Henderson } 2153b2167459SRichard Henderson 2154869051eaSRichard Henderson static DisasJumpType trans_cmpiclr(DisasContext *ctx, uint32_t insn) 2155b2167459SRichard Henderson { 2156b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 2157b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 2158b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2159b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 2160b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 2161869051eaSRichard Henderson DisasJumpType ret; 2162b2167459SRichard Henderson 2163b2167459SRichard Henderson if (cf) { 2164b2167459SRichard Henderson nullify_over(ctx); 2165b2167459SRichard Henderson } 2166b2167459SRichard Henderson 2167b2167459SRichard Henderson tcg_im = load_const(ctx, im); 2168b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 2169b2167459SRichard Henderson ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf); 2170b2167459SRichard Henderson 2171b2167459SRichard Henderson return nullify_end(ctx, ret); 2172b2167459SRichard Henderson } 2173b2167459SRichard Henderson 2174869051eaSRichard Henderson static DisasJumpType trans_ld_idx_i(DisasContext *ctx, uint32_t insn, 217596d6407fSRichard Henderson const DisasInsn *di) 217696d6407fSRichard Henderson { 217796d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 217896d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 217996d6407fSRichard Henderson unsigned sz = extract32(insn, 6, 2); 218096d6407fSRichard Henderson unsigned a = extract32(insn, 13, 1); 218196d6407fSRichard Henderson int disp = low_sextract(insn, 16, 5); 218296d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 218396d6407fSRichard Henderson int modify = (m ? (a ? -1 : 1) : 0); 218496d6407fSRichard Henderson TCGMemOp mop = MO_TE | sz; 218596d6407fSRichard Henderson 218696d6407fSRichard Henderson return do_load(ctx, rt, rb, 0, 0, disp, modify, mop); 218796d6407fSRichard Henderson } 218896d6407fSRichard Henderson 2189869051eaSRichard Henderson static DisasJumpType trans_ld_idx_x(DisasContext *ctx, uint32_t insn, 219096d6407fSRichard Henderson const DisasInsn *di) 219196d6407fSRichard Henderson { 219296d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 219396d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 219496d6407fSRichard Henderson unsigned sz = extract32(insn, 6, 2); 219596d6407fSRichard Henderson unsigned u = extract32(insn, 13, 1); 219696d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 219796d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 219896d6407fSRichard Henderson TCGMemOp mop = MO_TE | sz; 219996d6407fSRichard Henderson 220096d6407fSRichard Henderson return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop); 220196d6407fSRichard Henderson } 220296d6407fSRichard Henderson 2203869051eaSRichard Henderson static DisasJumpType trans_st_idx_i(DisasContext *ctx, uint32_t insn, 220496d6407fSRichard Henderson const DisasInsn *di) 220596d6407fSRichard Henderson { 220696d6407fSRichard Henderson int disp = low_sextract(insn, 0, 5); 220796d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 220896d6407fSRichard Henderson unsigned sz = extract32(insn, 6, 2); 220996d6407fSRichard Henderson unsigned a = extract32(insn, 13, 1); 221096d6407fSRichard Henderson unsigned rr = extract32(insn, 16, 5); 221196d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 221296d6407fSRichard Henderson int modify = (m ? (a ? -1 : 1) : 0); 221396d6407fSRichard Henderson TCGMemOp mop = MO_TE | sz; 221496d6407fSRichard Henderson 221596d6407fSRichard Henderson return do_store(ctx, rr, rb, disp, modify, mop); 221696d6407fSRichard Henderson } 221796d6407fSRichard Henderson 2218869051eaSRichard Henderson static DisasJumpType trans_ldcw(DisasContext *ctx, uint32_t insn, 221996d6407fSRichard Henderson const DisasInsn *di) 222096d6407fSRichard Henderson { 222196d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 222296d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 222396d6407fSRichard Henderson unsigned i = extract32(insn, 12, 1); 222496d6407fSRichard Henderson unsigned au = extract32(insn, 13, 1); 222596d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 222696d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 222796d6407fSRichard Henderson TCGMemOp mop = MO_TEUL | MO_ALIGN_16; 222896d6407fSRichard Henderson TCGv zero, addr, base, dest; 222996d6407fSRichard Henderson int modify, disp = 0, scale = 0; 223096d6407fSRichard Henderson 223196d6407fSRichard Henderson nullify_over(ctx); 223296d6407fSRichard Henderson 223396d6407fSRichard Henderson /* ??? Share more code with do_load and do_load_{32,64}. */ 223496d6407fSRichard Henderson 223596d6407fSRichard Henderson if (i) { 223696d6407fSRichard Henderson modify = (m ? (au ? -1 : 1) : 0); 223796d6407fSRichard Henderson disp = low_sextract(rx, 0, 5); 223896d6407fSRichard Henderson rx = 0; 223996d6407fSRichard Henderson } else { 224096d6407fSRichard Henderson modify = m; 224196d6407fSRichard Henderson if (au) { 224296d6407fSRichard Henderson scale = mop & MO_SIZE; 224396d6407fSRichard Henderson } 224496d6407fSRichard Henderson } 224596d6407fSRichard Henderson if (modify) { 224696d6407fSRichard Henderson /* Base register modification. Make sure if RT == RB, we see 224796d6407fSRichard Henderson the result of the load. */ 224896d6407fSRichard Henderson dest = get_temp(ctx); 224996d6407fSRichard Henderson } else { 225096d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 225196d6407fSRichard Henderson } 225296d6407fSRichard Henderson 225396d6407fSRichard Henderson addr = tcg_temp_new(); 225496d6407fSRichard Henderson base = load_gpr(ctx, rb); 225596d6407fSRichard Henderson if (rx) { 225696d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 225796d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 225896d6407fSRichard Henderson } else { 225996d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 226096d6407fSRichard Henderson } 226196d6407fSRichard Henderson 226296d6407fSRichard Henderson zero = tcg_const_tl(0); 226396d6407fSRichard Henderson tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base), 226496d6407fSRichard Henderson zero, MMU_USER_IDX, mop); 226596d6407fSRichard Henderson if (modify) { 226696d6407fSRichard Henderson save_gpr(ctx, rb, addr); 226796d6407fSRichard Henderson } 226896d6407fSRichard Henderson save_gpr(ctx, rt, dest); 226996d6407fSRichard Henderson 2270869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 227196d6407fSRichard Henderson } 227296d6407fSRichard Henderson 2273869051eaSRichard Henderson static DisasJumpType trans_stby(DisasContext *ctx, uint32_t insn, 227496d6407fSRichard Henderson const DisasInsn *di) 227596d6407fSRichard Henderson { 227696d6407fSRichard Henderson target_long disp = low_sextract(insn, 0, 5); 227796d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 227896d6407fSRichard Henderson unsigned a = extract32(insn, 13, 1); 227996d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 228096d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 228196d6407fSRichard Henderson TCGv addr, val; 228296d6407fSRichard Henderson 228396d6407fSRichard Henderson nullify_over(ctx); 228496d6407fSRichard Henderson 228596d6407fSRichard Henderson addr = tcg_temp_new(); 228696d6407fSRichard Henderson if (m || disp == 0) { 228796d6407fSRichard Henderson tcg_gen_mov_tl(addr, load_gpr(ctx, rb)); 228896d6407fSRichard Henderson } else { 228996d6407fSRichard Henderson tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp); 229096d6407fSRichard Henderson } 229196d6407fSRichard Henderson val = load_gpr(ctx, rt); 229296d6407fSRichard Henderson 229396d6407fSRichard Henderson if (a) { 2294*f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 2295*f9f46db4SEmilio G. Cota gen_helper_stby_e_parallel(cpu_env, addr, val); 2296*f9f46db4SEmilio G. Cota } else { 229796d6407fSRichard Henderson gen_helper_stby_e(cpu_env, addr, val); 2298*f9f46db4SEmilio G. Cota } 2299*f9f46db4SEmilio G. Cota } else { 2300*f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 2301*f9f46db4SEmilio G. Cota gen_helper_stby_b_parallel(cpu_env, addr, val); 230296d6407fSRichard Henderson } else { 230396d6407fSRichard Henderson gen_helper_stby_b(cpu_env, addr, val); 230496d6407fSRichard Henderson } 2305*f9f46db4SEmilio G. Cota } 230696d6407fSRichard Henderson 230796d6407fSRichard Henderson if (m) { 230896d6407fSRichard Henderson tcg_gen_addi_tl(addr, addr, disp); 230996d6407fSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 231096d6407fSRichard Henderson save_gpr(ctx, rb, addr); 231196d6407fSRichard Henderson } 231296d6407fSRichard Henderson tcg_temp_free(addr); 231396d6407fSRichard Henderson 2314869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 231596d6407fSRichard Henderson } 231696d6407fSRichard Henderson 231796d6407fSRichard Henderson static const DisasInsn table_index_mem[] = { 231896d6407fSRichard Henderson { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */ 231996d6407fSRichard Henderson { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */ 232096d6407fSRichard Henderson { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */ 232196d6407fSRichard Henderson { 0x0c0001c0u, 0xfc0003c0, trans_ldcw }, 232296d6407fSRichard Henderson { 0x0c001300u, 0xfc0013c0, trans_stby }, 232396d6407fSRichard Henderson }; 232496d6407fSRichard Henderson 2325869051eaSRichard Henderson static DisasJumpType trans_ldil(DisasContext *ctx, uint32_t insn) 2326b2167459SRichard Henderson { 2327b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 2328b2167459SRichard Henderson target_long i = assemble_21(insn); 2329b2167459SRichard Henderson TCGv tcg_rt = dest_gpr(ctx, rt); 2330b2167459SRichard Henderson 2331b2167459SRichard Henderson tcg_gen_movi_tl(tcg_rt, i); 2332b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 2333b2167459SRichard Henderson cond_free(&ctx->null_cond); 2334b2167459SRichard Henderson 2335869051eaSRichard Henderson return DISAS_NEXT; 2336b2167459SRichard Henderson } 2337b2167459SRichard Henderson 2338869051eaSRichard Henderson static DisasJumpType trans_addil(DisasContext *ctx, uint32_t insn) 2339b2167459SRichard Henderson { 2340b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 2341b2167459SRichard Henderson target_long i = assemble_21(insn); 2342b2167459SRichard Henderson TCGv tcg_rt = load_gpr(ctx, rt); 2343b2167459SRichard Henderson TCGv tcg_r1 = dest_gpr(ctx, 1); 2344b2167459SRichard Henderson 2345b2167459SRichard Henderson tcg_gen_addi_tl(tcg_r1, tcg_rt, i); 2346b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 2347b2167459SRichard Henderson cond_free(&ctx->null_cond); 2348b2167459SRichard Henderson 2349869051eaSRichard Henderson return DISAS_NEXT; 2350b2167459SRichard Henderson } 2351b2167459SRichard Henderson 2352869051eaSRichard Henderson static DisasJumpType trans_ldo(DisasContext *ctx, uint32_t insn) 2353b2167459SRichard Henderson { 2354b2167459SRichard Henderson unsigned rb = extract32(insn, 21, 5); 2355b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2356b2167459SRichard Henderson target_long i = assemble_16(insn); 2357b2167459SRichard Henderson TCGv tcg_rt = dest_gpr(ctx, rt); 2358b2167459SRichard Henderson 2359b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 2360b2167459SRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */ 2361b2167459SRichard Henderson if (rb == 0) { 2362b2167459SRichard Henderson tcg_gen_movi_tl(tcg_rt, i); 2363b2167459SRichard Henderson } else { 2364b2167459SRichard Henderson tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i); 2365b2167459SRichard Henderson } 2366b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 2367b2167459SRichard Henderson cond_free(&ctx->null_cond); 2368b2167459SRichard Henderson 2369869051eaSRichard Henderson return DISAS_NEXT; 2370b2167459SRichard Henderson } 2371b2167459SRichard Henderson 2372869051eaSRichard Henderson static DisasJumpType trans_load(DisasContext *ctx, uint32_t insn, 237396d6407fSRichard Henderson bool is_mod, TCGMemOp mop) 237496d6407fSRichard Henderson { 237596d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 237696d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 237796d6407fSRichard Henderson target_long i = assemble_16(insn); 237896d6407fSRichard Henderson 237996d6407fSRichard Henderson return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop); 238096d6407fSRichard Henderson } 238196d6407fSRichard Henderson 2382869051eaSRichard Henderson static DisasJumpType trans_load_w(DisasContext *ctx, uint32_t insn) 238396d6407fSRichard Henderson { 238496d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 238596d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 238696d6407fSRichard Henderson target_long i = assemble_16a(insn); 238796d6407fSRichard Henderson unsigned ext2 = extract32(insn, 1, 2); 238896d6407fSRichard Henderson 238996d6407fSRichard Henderson switch (ext2) { 239096d6407fSRichard Henderson case 0: 239196d6407fSRichard Henderson case 1: 239296d6407fSRichard Henderson /* FLDW without modification. */ 239396d6407fSRichard Henderson return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0); 239496d6407fSRichard Henderson case 2: 239596d6407fSRichard Henderson /* LDW with modification. Note that the sign of I selects 239696d6407fSRichard Henderson post-dec vs pre-inc. */ 239796d6407fSRichard Henderson return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL); 239896d6407fSRichard Henderson default: 239996d6407fSRichard Henderson return gen_illegal(ctx); 240096d6407fSRichard Henderson } 240196d6407fSRichard Henderson } 240296d6407fSRichard Henderson 2403869051eaSRichard Henderson static DisasJumpType trans_fload_mod(DisasContext *ctx, uint32_t insn) 240496d6407fSRichard Henderson { 240596d6407fSRichard Henderson target_long i = assemble_16a(insn); 240696d6407fSRichard Henderson unsigned t1 = extract32(insn, 1, 1); 240796d6407fSRichard Henderson unsigned a = extract32(insn, 2, 1); 240896d6407fSRichard Henderson unsigned t0 = extract32(insn, 16, 5); 240996d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 241096d6407fSRichard Henderson 241196d6407fSRichard Henderson /* FLDW with modification. */ 241296d6407fSRichard Henderson return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1)); 241396d6407fSRichard Henderson } 241496d6407fSRichard Henderson 2415869051eaSRichard Henderson static DisasJumpType trans_store(DisasContext *ctx, uint32_t insn, 241696d6407fSRichard Henderson bool is_mod, TCGMemOp mop) 241796d6407fSRichard Henderson { 241896d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 241996d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 242096d6407fSRichard Henderson target_long i = assemble_16(insn); 242196d6407fSRichard Henderson 242296d6407fSRichard Henderson return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop); 242396d6407fSRichard Henderson } 242496d6407fSRichard Henderson 2425869051eaSRichard Henderson static DisasJumpType trans_store_w(DisasContext *ctx, uint32_t insn) 242696d6407fSRichard Henderson { 242796d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 242896d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 242996d6407fSRichard Henderson target_long i = assemble_16a(insn); 243096d6407fSRichard Henderson unsigned ext2 = extract32(insn, 1, 2); 243196d6407fSRichard Henderson 243296d6407fSRichard Henderson switch (ext2) { 243396d6407fSRichard Henderson case 0: 243496d6407fSRichard Henderson case 1: 243596d6407fSRichard Henderson /* FSTW without modification. */ 243696d6407fSRichard Henderson return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0); 243796d6407fSRichard Henderson case 2: 243896d6407fSRichard Henderson /* LDW with modification. */ 243996d6407fSRichard Henderson return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL); 244096d6407fSRichard Henderson default: 244196d6407fSRichard Henderson return gen_illegal(ctx); 244296d6407fSRichard Henderson } 244396d6407fSRichard Henderson } 244496d6407fSRichard Henderson 2445869051eaSRichard Henderson static DisasJumpType trans_fstore_mod(DisasContext *ctx, uint32_t insn) 244696d6407fSRichard Henderson { 244796d6407fSRichard Henderson target_long i = assemble_16a(insn); 244896d6407fSRichard Henderson unsigned t1 = extract32(insn, 1, 1); 244996d6407fSRichard Henderson unsigned a = extract32(insn, 2, 1); 245096d6407fSRichard Henderson unsigned t0 = extract32(insn, 16, 5); 245196d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 245296d6407fSRichard Henderson 245396d6407fSRichard Henderson /* FSTW with modification. */ 245496d6407fSRichard Henderson return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1)); 245596d6407fSRichard Henderson } 245696d6407fSRichard Henderson 2457869051eaSRichard Henderson static DisasJumpType trans_copr_w(DisasContext *ctx, uint32_t insn) 245896d6407fSRichard Henderson { 245996d6407fSRichard Henderson unsigned t0 = extract32(insn, 0, 5); 246096d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 246196d6407fSRichard Henderson unsigned t1 = extract32(insn, 6, 1); 246296d6407fSRichard Henderson unsigned ext3 = extract32(insn, 7, 3); 246396d6407fSRichard Henderson /* unsigned cc = extract32(insn, 10, 2); */ 246496d6407fSRichard Henderson unsigned i = extract32(insn, 12, 1); 246596d6407fSRichard Henderson unsigned ua = extract32(insn, 13, 1); 246696d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 246796d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 246896d6407fSRichard Henderson unsigned rt = t1 * 32 + t0; 246996d6407fSRichard Henderson int modify = (m ? (ua ? -1 : 1) : 0); 247096d6407fSRichard Henderson int disp, scale; 247196d6407fSRichard Henderson 247296d6407fSRichard Henderson if (i == 0) { 247396d6407fSRichard Henderson scale = (ua ? 2 : 0); 247496d6407fSRichard Henderson disp = 0; 247596d6407fSRichard Henderson modify = m; 247696d6407fSRichard Henderson } else { 247796d6407fSRichard Henderson disp = low_sextract(rx, 0, 5); 247896d6407fSRichard Henderson scale = 0; 247996d6407fSRichard Henderson rx = 0; 248096d6407fSRichard Henderson modify = (m ? (ua ? -1 : 1) : 0); 248196d6407fSRichard Henderson } 248296d6407fSRichard Henderson 248396d6407fSRichard Henderson switch (ext3) { 248496d6407fSRichard Henderson case 0: /* FLDW */ 248596d6407fSRichard Henderson return do_floadw(ctx, rt, rb, rx, scale, disp, modify); 248696d6407fSRichard Henderson case 4: /* FSTW */ 248796d6407fSRichard Henderson return do_fstorew(ctx, rt, rb, rx, scale, disp, modify); 248896d6407fSRichard Henderson } 248996d6407fSRichard Henderson return gen_illegal(ctx); 249096d6407fSRichard Henderson } 249196d6407fSRichard Henderson 2492869051eaSRichard Henderson static DisasJumpType trans_copr_dw(DisasContext *ctx, uint32_t insn) 249396d6407fSRichard Henderson { 249496d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 249596d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 249696d6407fSRichard Henderson unsigned ext4 = extract32(insn, 6, 4); 249796d6407fSRichard Henderson /* unsigned cc = extract32(insn, 10, 2); */ 249896d6407fSRichard Henderson unsigned i = extract32(insn, 12, 1); 249996d6407fSRichard Henderson unsigned ua = extract32(insn, 13, 1); 250096d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 250196d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 250296d6407fSRichard Henderson int modify = (m ? (ua ? -1 : 1) : 0); 250396d6407fSRichard Henderson int disp, scale; 250496d6407fSRichard Henderson 250596d6407fSRichard Henderson if (i == 0) { 250696d6407fSRichard Henderson scale = (ua ? 3 : 0); 250796d6407fSRichard Henderson disp = 0; 250896d6407fSRichard Henderson modify = m; 250996d6407fSRichard Henderson } else { 251096d6407fSRichard Henderson disp = low_sextract(rx, 0, 5); 251196d6407fSRichard Henderson scale = 0; 251296d6407fSRichard Henderson rx = 0; 251396d6407fSRichard Henderson modify = (m ? (ua ? -1 : 1) : 0); 251496d6407fSRichard Henderson } 251596d6407fSRichard Henderson 251696d6407fSRichard Henderson switch (ext4) { 251796d6407fSRichard Henderson case 0: /* FLDD */ 251896d6407fSRichard Henderson return do_floadd(ctx, rt, rb, rx, scale, disp, modify); 251996d6407fSRichard Henderson case 8: /* FSTD */ 252096d6407fSRichard Henderson return do_fstored(ctx, rt, rb, rx, scale, disp, modify); 252196d6407fSRichard Henderson default: 252296d6407fSRichard Henderson return gen_illegal(ctx); 252396d6407fSRichard Henderson } 252496d6407fSRichard Henderson } 252596d6407fSRichard Henderson 2526869051eaSRichard Henderson static DisasJumpType trans_cmpb(DisasContext *ctx, uint32_t insn, 252798cd9ca7SRichard Henderson bool is_true, bool is_imm, bool is_dw) 252898cd9ca7SRichard Henderson { 252998cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 253098cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 253198cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 253298cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 253398cd9ca7SRichard Henderson unsigned cf = c * 2 + !is_true; 253498cd9ca7SRichard Henderson TCGv dest, in1, in2, sv; 253598cd9ca7SRichard Henderson DisasCond cond; 253698cd9ca7SRichard Henderson 253798cd9ca7SRichard Henderson nullify_over(ctx); 253898cd9ca7SRichard Henderson 253998cd9ca7SRichard Henderson if (is_imm) { 254098cd9ca7SRichard Henderson in1 = load_const(ctx, low_sextract(insn, 16, 5)); 254198cd9ca7SRichard Henderson } else { 254298cd9ca7SRichard Henderson in1 = load_gpr(ctx, extract32(insn, 16, 5)); 254398cd9ca7SRichard Henderson } 254498cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 254598cd9ca7SRichard Henderson dest = get_temp(ctx); 254698cd9ca7SRichard Henderson 254798cd9ca7SRichard Henderson tcg_gen_sub_tl(dest, in1, in2); 254898cd9ca7SRichard Henderson 254998cd9ca7SRichard Henderson TCGV_UNUSED(sv); 255098cd9ca7SRichard Henderson if (c == 6) { 255198cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 255298cd9ca7SRichard Henderson } 255398cd9ca7SRichard Henderson 255498cd9ca7SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 255598cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 255698cd9ca7SRichard Henderson } 255798cd9ca7SRichard Henderson 2558869051eaSRichard Henderson static DisasJumpType trans_addb(DisasContext *ctx, uint32_t insn, 255998cd9ca7SRichard Henderson bool is_true, bool is_imm) 256098cd9ca7SRichard Henderson { 256198cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 256298cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 256398cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 256498cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 256598cd9ca7SRichard Henderson unsigned cf = c * 2 + !is_true; 256698cd9ca7SRichard Henderson TCGv dest, in1, in2, sv, cb_msb; 256798cd9ca7SRichard Henderson DisasCond cond; 256898cd9ca7SRichard Henderson 256998cd9ca7SRichard Henderson nullify_over(ctx); 257098cd9ca7SRichard Henderson 257198cd9ca7SRichard Henderson if (is_imm) { 257298cd9ca7SRichard Henderson in1 = load_const(ctx, low_sextract(insn, 16, 5)); 257398cd9ca7SRichard Henderson } else { 257498cd9ca7SRichard Henderson in1 = load_gpr(ctx, extract32(insn, 16, 5)); 257598cd9ca7SRichard Henderson } 257698cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 257798cd9ca7SRichard Henderson dest = dest_gpr(ctx, r); 257898cd9ca7SRichard Henderson TCGV_UNUSED(sv); 257998cd9ca7SRichard Henderson TCGV_UNUSED(cb_msb); 258098cd9ca7SRichard Henderson 258198cd9ca7SRichard Henderson switch (c) { 258298cd9ca7SRichard Henderson default: 258398cd9ca7SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 258498cd9ca7SRichard Henderson break; 258598cd9ca7SRichard Henderson case 4: case 5: 258698cd9ca7SRichard Henderson cb_msb = get_temp(ctx); 258798cd9ca7SRichard Henderson tcg_gen_movi_tl(cb_msb, 0); 258898cd9ca7SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb); 258998cd9ca7SRichard Henderson break; 259098cd9ca7SRichard Henderson case 6: 259198cd9ca7SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 259298cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 259398cd9ca7SRichard Henderson break; 259498cd9ca7SRichard Henderson } 259598cd9ca7SRichard Henderson 259698cd9ca7SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 259798cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 259898cd9ca7SRichard Henderson } 259998cd9ca7SRichard Henderson 2600869051eaSRichard Henderson static DisasJumpType trans_bb(DisasContext *ctx, uint32_t insn) 260198cd9ca7SRichard Henderson { 260298cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 260398cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 260498cd9ca7SRichard Henderson unsigned c = extract32(insn, 15, 1); 260598cd9ca7SRichard Henderson unsigned r = extract32(insn, 16, 5); 260698cd9ca7SRichard Henderson unsigned p = extract32(insn, 21, 5); 260798cd9ca7SRichard Henderson unsigned i = extract32(insn, 26, 1); 260898cd9ca7SRichard Henderson TCGv tmp, tcg_r; 260998cd9ca7SRichard Henderson DisasCond cond; 261098cd9ca7SRichard Henderson 261198cd9ca7SRichard Henderson nullify_over(ctx); 261298cd9ca7SRichard Henderson 261398cd9ca7SRichard Henderson tmp = tcg_temp_new(); 261498cd9ca7SRichard Henderson tcg_r = load_gpr(ctx, r); 261598cd9ca7SRichard Henderson if (i) { 261698cd9ca7SRichard Henderson tcg_gen_shli_tl(tmp, tcg_r, p); 261798cd9ca7SRichard Henderson } else { 261898cd9ca7SRichard Henderson tcg_gen_shl_tl(tmp, tcg_r, cpu_sar); 261998cd9ca7SRichard Henderson } 262098cd9ca7SRichard Henderson 262198cd9ca7SRichard Henderson cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp); 262298cd9ca7SRichard Henderson tcg_temp_free(tmp); 262398cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 262498cd9ca7SRichard Henderson } 262598cd9ca7SRichard Henderson 2626869051eaSRichard Henderson static DisasJumpType trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm) 262798cd9ca7SRichard Henderson { 262898cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 262998cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 263098cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 263198cd9ca7SRichard Henderson unsigned t = extract32(insn, 16, 5); 263298cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 263398cd9ca7SRichard Henderson TCGv dest; 263498cd9ca7SRichard Henderson DisasCond cond; 263598cd9ca7SRichard Henderson 263698cd9ca7SRichard Henderson nullify_over(ctx); 263798cd9ca7SRichard Henderson 263898cd9ca7SRichard Henderson dest = dest_gpr(ctx, r); 263998cd9ca7SRichard Henderson if (is_imm) { 264098cd9ca7SRichard Henderson tcg_gen_movi_tl(dest, low_sextract(t, 0, 5)); 264198cd9ca7SRichard Henderson } else if (t == 0) { 264298cd9ca7SRichard Henderson tcg_gen_movi_tl(dest, 0); 264398cd9ca7SRichard Henderson } else { 264498cd9ca7SRichard Henderson tcg_gen_mov_tl(dest, cpu_gr[t]); 264598cd9ca7SRichard Henderson } 264698cd9ca7SRichard Henderson 264798cd9ca7SRichard Henderson cond = do_sed_cond(c, dest); 264898cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 264998cd9ca7SRichard Henderson } 265098cd9ca7SRichard Henderson 2651869051eaSRichard Henderson static DisasJumpType trans_shrpw_sar(DisasContext *ctx, uint32_t insn, 26520b1347d2SRichard Henderson const DisasInsn *di) 26530b1347d2SRichard Henderson { 26540b1347d2SRichard Henderson unsigned rt = extract32(insn, 0, 5); 26550b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 26560b1347d2SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 26570b1347d2SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 26580b1347d2SRichard Henderson TCGv dest; 26590b1347d2SRichard Henderson 26600b1347d2SRichard Henderson if (c) { 26610b1347d2SRichard Henderson nullify_over(ctx); 26620b1347d2SRichard Henderson } 26630b1347d2SRichard Henderson 26640b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 26650b1347d2SRichard Henderson if (r1 == 0) { 26660b1347d2SRichard Henderson tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2)); 26670b1347d2SRichard Henderson tcg_gen_shr_tl(dest, dest, cpu_sar); 26680b1347d2SRichard Henderson } else if (r1 == r2) { 26690b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 26700b1347d2SRichard Henderson tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2)); 26710b1347d2SRichard Henderson tcg_gen_rotr_i32(t32, t32, cpu_sar); 26720b1347d2SRichard Henderson tcg_gen_extu_i32_tl(dest, t32); 26730b1347d2SRichard Henderson tcg_temp_free_i32(t32); 26740b1347d2SRichard Henderson } else { 26750b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 26760b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 26770b1347d2SRichard Henderson 26780b1347d2SRichard Henderson tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1)); 26790b1347d2SRichard Henderson tcg_gen_extu_tl_i64(s, cpu_sar); 26800b1347d2SRichard Henderson tcg_gen_shr_i64(t, t, s); 26810b1347d2SRichard Henderson tcg_gen_trunc_i64_tl(dest, t); 26820b1347d2SRichard Henderson 26830b1347d2SRichard Henderson tcg_temp_free_i64(t); 26840b1347d2SRichard Henderson tcg_temp_free_i64(s); 26850b1347d2SRichard Henderson } 26860b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 26870b1347d2SRichard Henderson 26880b1347d2SRichard Henderson /* Install the new nullification. */ 26890b1347d2SRichard Henderson cond_free(&ctx->null_cond); 26900b1347d2SRichard Henderson if (c) { 26910b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 26920b1347d2SRichard Henderson } 2693869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 26940b1347d2SRichard Henderson } 26950b1347d2SRichard Henderson 2696869051eaSRichard Henderson static DisasJumpType trans_shrpw_imm(DisasContext *ctx, uint32_t insn, 26970b1347d2SRichard Henderson const DisasInsn *di) 26980b1347d2SRichard Henderson { 26990b1347d2SRichard Henderson unsigned rt = extract32(insn, 0, 5); 27000b1347d2SRichard Henderson unsigned cpos = extract32(insn, 5, 5); 27010b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 27020b1347d2SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 27030b1347d2SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 27040b1347d2SRichard Henderson unsigned sa = 31 - cpos; 27050b1347d2SRichard Henderson TCGv dest, t2; 27060b1347d2SRichard Henderson 27070b1347d2SRichard Henderson if (c) { 27080b1347d2SRichard Henderson nullify_over(ctx); 27090b1347d2SRichard Henderson } 27100b1347d2SRichard Henderson 27110b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 27120b1347d2SRichard Henderson t2 = load_gpr(ctx, r2); 27130b1347d2SRichard Henderson if (r1 == r2) { 27140b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 27150b1347d2SRichard Henderson tcg_gen_trunc_tl_i32(t32, t2); 27160b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 27170b1347d2SRichard Henderson tcg_gen_extu_i32_tl(dest, t32); 27180b1347d2SRichard Henderson tcg_temp_free_i32(t32); 27190b1347d2SRichard Henderson } else if (r1 == 0) { 27200b1347d2SRichard Henderson tcg_gen_extract_tl(dest, t2, sa, 32 - sa); 27210b1347d2SRichard Henderson } else { 27220b1347d2SRichard Henderson TCGv t0 = tcg_temp_new(); 27230b1347d2SRichard Henderson tcg_gen_extract_tl(t0, t2, sa, 32 - sa); 27240b1347d2SRichard Henderson tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa); 27250b1347d2SRichard Henderson tcg_temp_free(t0); 27260b1347d2SRichard Henderson } 27270b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 27280b1347d2SRichard Henderson 27290b1347d2SRichard Henderson /* Install the new nullification. */ 27300b1347d2SRichard Henderson cond_free(&ctx->null_cond); 27310b1347d2SRichard Henderson if (c) { 27320b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 27330b1347d2SRichard Henderson } 2734869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 27350b1347d2SRichard Henderson } 27360b1347d2SRichard Henderson 2737869051eaSRichard Henderson static DisasJumpType trans_extrw_sar(DisasContext *ctx, uint32_t insn, 27380b1347d2SRichard Henderson const DisasInsn *di) 27390b1347d2SRichard Henderson { 27400b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 27410b1347d2SRichard Henderson unsigned is_se = extract32(insn, 10, 1); 27420b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 27430b1347d2SRichard Henderson unsigned rt = extract32(insn, 16, 5); 27440b1347d2SRichard Henderson unsigned rr = extract32(insn, 21, 5); 27450b1347d2SRichard Henderson unsigned len = 32 - clen; 27460b1347d2SRichard Henderson TCGv dest, src, tmp; 27470b1347d2SRichard Henderson 27480b1347d2SRichard Henderson if (c) { 27490b1347d2SRichard Henderson nullify_over(ctx); 27500b1347d2SRichard Henderson } 27510b1347d2SRichard Henderson 27520b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 27530b1347d2SRichard Henderson src = load_gpr(ctx, rr); 27540b1347d2SRichard Henderson tmp = tcg_temp_new(); 27550b1347d2SRichard Henderson 27560b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 27570b1347d2SRichard Henderson tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1); 27580b1347d2SRichard Henderson if (is_se) { 27590b1347d2SRichard Henderson tcg_gen_sar_tl(dest, src, tmp); 27600b1347d2SRichard Henderson tcg_gen_sextract_tl(dest, dest, 0, len); 27610b1347d2SRichard Henderson } else { 27620b1347d2SRichard Henderson tcg_gen_shr_tl(dest, src, tmp); 27630b1347d2SRichard Henderson tcg_gen_extract_tl(dest, dest, 0, len); 27640b1347d2SRichard Henderson } 27650b1347d2SRichard Henderson tcg_temp_free(tmp); 27660b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 27670b1347d2SRichard Henderson 27680b1347d2SRichard Henderson /* Install the new nullification. */ 27690b1347d2SRichard Henderson cond_free(&ctx->null_cond); 27700b1347d2SRichard Henderson if (c) { 27710b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 27720b1347d2SRichard Henderson } 2773869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 27740b1347d2SRichard Henderson } 27750b1347d2SRichard Henderson 2776869051eaSRichard Henderson static DisasJumpType trans_extrw_imm(DisasContext *ctx, uint32_t insn, 27770b1347d2SRichard Henderson const DisasInsn *di) 27780b1347d2SRichard Henderson { 27790b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 27800b1347d2SRichard Henderson unsigned pos = extract32(insn, 5, 5); 27810b1347d2SRichard Henderson unsigned is_se = extract32(insn, 10, 1); 27820b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 27830b1347d2SRichard Henderson unsigned rt = extract32(insn, 16, 5); 27840b1347d2SRichard Henderson unsigned rr = extract32(insn, 21, 5); 27850b1347d2SRichard Henderson unsigned len = 32 - clen; 27860b1347d2SRichard Henderson unsigned cpos = 31 - pos; 27870b1347d2SRichard Henderson TCGv dest, src; 27880b1347d2SRichard Henderson 27890b1347d2SRichard Henderson if (c) { 27900b1347d2SRichard Henderson nullify_over(ctx); 27910b1347d2SRichard Henderson } 27920b1347d2SRichard Henderson 27930b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 27940b1347d2SRichard Henderson src = load_gpr(ctx, rr); 27950b1347d2SRichard Henderson if (is_se) { 27960b1347d2SRichard Henderson tcg_gen_sextract_tl(dest, src, cpos, len); 27970b1347d2SRichard Henderson } else { 27980b1347d2SRichard Henderson tcg_gen_extract_tl(dest, src, cpos, len); 27990b1347d2SRichard Henderson } 28000b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 28010b1347d2SRichard Henderson 28020b1347d2SRichard Henderson /* Install the new nullification. */ 28030b1347d2SRichard Henderson cond_free(&ctx->null_cond); 28040b1347d2SRichard Henderson if (c) { 28050b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 28060b1347d2SRichard Henderson } 2807869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 28080b1347d2SRichard Henderson } 28090b1347d2SRichard Henderson 28100b1347d2SRichard Henderson static const DisasInsn table_sh_ex[] = { 28110b1347d2SRichard Henderson { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar }, 28120b1347d2SRichard Henderson { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm }, 28130b1347d2SRichard Henderson { 0xd0001000u, 0xfc001be0u, trans_extrw_sar }, 28140b1347d2SRichard Henderson { 0xd0001800u, 0xfc001800u, trans_extrw_imm }, 28150b1347d2SRichard Henderson }; 28160b1347d2SRichard Henderson 2817869051eaSRichard Henderson static DisasJumpType trans_depw_imm_c(DisasContext *ctx, uint32_t insn, 28180b1347d2SRichard Henderson const DisasInsn *di) 28190b1347d2SRichard Henderson { 28200b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 28210b1347d2SRichard Henderson unsigned cpos = extract32(insn, 5, 5); 28220b1347d2SRichard Henderson unsigned nz = extract32(insn, 10, 1); 28230b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 28240b1347d2SRichard Henderson target_long val = low_sextract(insn, 16, 5); 28250b1347d2SRichard Henderson unsigned rt = extract32(insn, 21, 5); 28260b1347d2SRichard Henderson unsigned len = 32 - clen; 28270b1347d2SRichard Henderson target_long mask0, mask1; 28280b1347d2SRichard Henderson TCGv dest; 28290b1347d2SRichard Henderson 28300b1347d2SRichard Henderson if (c) { 28310b1347d2SRichard Henderson nullify_over(ctx); 28320b1347d2SRichard Henderson } 28330b1347d2SRichard Henderson if (cpos + len > 32) { 28340b1347d2SRichard Henderson len = 32 - cpos; 28350b1347d2SRichard Henderson } 28360b1347d2SRichard Henderson 28370b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 28380b1347d2SRichard Henderson mask0 = deposit64(0, cpos, len, val); 28390b1347d2SRichard Henderson mask1 = deposit64(-1, cpos, len, val); 28400b1347d2SRichard Henderson 28410b1347d2SRichard Henderson if (nz) { 28420b1347d2SRichard Henderson TCGv src = load_gpr(ctx, rt); 28430b1347d2SRichard Henderson if (mask1 != -1) { 28440b1347d2SRichard Henderson tcg_gen_andi_tl(dest, src, mask1); 28450b1347d2SRichard Henderson src = dest; 28460b1347d2SRichard Henderson } 28470b1347d2SRichard Henderson tcg_gen_ori_tl(dest, src, mask0); 28480b1347d2SRichard Henderson } else { 28490b1347d2SRichard Henderson tcg_gen_movi_tl(dest, mask0); 28500b1347d2SRichard Henderson } 28510b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 28520b1347d2SRichard Henderson 28530b1347d2SRichard Henderson /* Install the new nullification. */ 28540b1347d2SRichard Henderson cond_free(&ctx->null_cond); 28550b1347d2SRichard Henderson if (c) { 28560b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 28570b1347d2SRichard Henderson } 2858869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 28590b1347d2SRichard Henderson } 28600b1347d2SRichard Henderson 2861869051eaSRichard Henderson static DisasJumpType trans_depw_imm(DisasContext *ctx, uint32_t insn, 28620b1347d2SRichard Henderson const DisasInsn *di) 28630b1347d2SRichard Henderson { 28640b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 28650b1347d2SRichard Henderson unsigned cpos = extract32(insn, 5, 5); 28660b1347d2SRichard Henderson unsigned nz = extract32(insn, 10, 1); 28670b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 28680b1347d2SRichard Henderson unsigned rr = extract32(insn, 16, 5); 28690b1347d2SRichard Henderson unsigned rt = extract32(insn, 21, 5); 28700b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 28710b1347d2SRichard Henderson unsigned len = 32 - clen; 28720b1347d2SRichard Henderson TCGv dest, val; 28730b1347d2SRichard Henderson 28740b1347d2SRichard Henderson if (c) { 28750b1347d2SRichard Henderson nullify_over(ctx); 28760b1347d2SRichard Henderson } 28770b1347d2SRichard Henderson if (cpos + len > 32) { 28780b1347d2SRichard Henderson len = 32 - cpos; 28790b1347d2SRichard Henderson } 28800b1347d2SRichard Henderson 28810b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 28820b1347d2SRichard Henderson val = load_gpr(ctx, rr); 28830b1347d2SRichard Henderson if (rs == 0) { 28840b1347d2SRichard Henderson tcg_gen_deposit_z_tl(dest, val, cpos, len); 28850b1347d2SRichard Henderson } else { 28860b1347d2SRichard Henderson tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len); 28870b1347d2SRichard Henderson } 28880b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 28890b1347d2SRichard Henderson 28900b1347d2SRichard Henderson /* Install the new nullification. */ 28910b1347d2SRichard Henderson cond_free(&ctx->null_cond); 28920b1347d2SRichard Henderson if (c) { 28930b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 28940b1347d2SRichard Henderson } 2895869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 28960b1347d2SRichard Henderson } 28970b1347d2SRichard Henderson 2898869051eaSRichard Henderson static DisasJumpType trans_depw_sar(DisasContext *ctx, uint32_t insn, 28990b1347d2SRichard Henderson const DisasInsn *di) 29000b1347d2SRichard Henderson { 29010b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 29020b1347d2SRichard Henderson unsigned nz = extract32(insn, 10, 1); 29030b1347d2SRichard Henderson unsigned i = extract32(insn, 12, 1); 29040b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 29050b1347d2SRichard Henderson unsigned rt = extract32(insn, 21, 5); 29060b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 29070b1347d2SRichard Henderson unsigned len = 32 - clen; 29080b1347d2SRichard Henderson TCGv val, mask, tmp, shift, dest; 29090b1347d2SRichard Henderson unsigned msb = 1U << (len - 1); 29100b1347d2SRichard Henderson 29110b1347d2SRichard Henderson if (c) { 29120b1347d2SRichard Henderson nullify_over(ctx); 29130b1347d2SRichard Henderson } 29140b1347d2SRichard Henderson 29150b1347d2SRichard Henderson if (i) { 29160b1347d2SRichard Henderson val = load_const(ctx, low_sextract(insn, 16, 5)); 29170b1347d2SRichard Henderson } else { 29180b1347d2SRichard Henderson val = load_gpr(ctx, extract32(insn, 16, 5)); 29190b1347d2SRichard Henderson } 29200b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 29210b1347d2SRichard Henderson shift = tcg_temp_new(); 29220b1347d2SRichard Henderson tmp = tcg_temp_new(); 29230b1347d2SRichard Henderson 29240b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 29250b1347d2SRichard Henderson tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1); 29260b1347d2SRichard Henderson 29270b1347d2SRichard Henderson mask = tcg_const_tl(msb + (msb - 1)); 29280b1347d2SRichard Henderson tcg_gen_and_tl(tmp, val, mask); 29290b1347d2SRichard Henderson if (rs) { 29300b1347d2SRichard Henderson tcg_gen_shl_tl(mask, mask, shift); 29310b1347d2SRichard Henderson tcg_gen_shl_tl(tmp, tmp, shift); 29320b1347d2SRichard Henderson tcg_gen_andc_tl(dest, cpu_gr[rs], mask); 29330b1347d2SRichard Henderson tcg_gen_or_tl(dest, dest, tmp); 29340b1347d2SRichard Henderson } else { 29350b1347d2SRichard Henderson tcg_gen_shl_tl(dest, tmp, shift); 29360b1347d2SRichard Henderson } 29370b1347d2SRichard Henderson tcg_temp_free(shift); 29380b1347d2SRichard Henderson tcg_temp_free(mask); 29390b1347d2SRichard Henderson tcg_temp_free(tmp); 29400b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 29410b1347d2SRichard Henderson 29420b1347d2SRichard Henderson /* Install the new nullification. */ 29430b1347d2SRichard Henderson cond_free(&ctx->null_cond); 29440b1347d2SRichard Henderson if (c) { 29450b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 29460b1347d2SRichard Henderson } 2947869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 29480b1347d2SRichard Henderson } 29490b1347d2SRichard Henderson 29500b1347d2SRichard Henderson static const DisasInsn table_depw[] = { 29510b1347d2SRichard Henderson { 0xd4000000u, 0xfc000be0u, trans_depw_sar }, 29520b1347d2SRichard Henderson { 0xd4000800u, 0xfc001800u, trans_depw_imm }, 29530b1347d2SRichard Henderson { 0xd4001800u, 0xfc001800u, trans_depw_imm_c }, 29540b1347d2SRichard Henderson }; 29550b1347d2SRichard Henderson 2956869051eaSRichard Henderson static DisasJumpType trans_be(DisasContext *ctx, uint32_t insn, bool is_l) 295798cd9ca7SRichard Henderson { 295898cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 295998cd9ca7SRichard Henderson unsigned b = extract32(insn, 21, 5); 296098cd9ca7SRichard Henderson target_long disp = assemble_17(insn); 296198cd9ca7SRichard Henderson 296298cd9ca7SRichard Henderson /* unsigned s = low_uextract(insn, 13, 3); */ 296398cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 296498cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 296598cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 296698cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 296798cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 296898cd9ca7SRichard Henderson 296998cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 297098cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 297198cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 297298cd9ca7SRichard Henderson if (b == 0) { 297398cd9ca7SRichard Henderson return do_dbranch(ctx, disp, is_l ? 31 : 0, n); 297498cd9ca7SRichard Henderson } else { 297598cd9ca7SRichard Henderson TCGv tmp = get_temp(ctx); 297698cd9ca7SRichard Henderson tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp); 297798cd9ca7SRichard Henderson return do_ibranch(ctx, tmp, is_l ? 31 : 0, n); 297898cd9ca7SRichard Henderson } 297998cd9ca7SRichard Henderson } 298098cd9ca7SRichard Henderson 2981869051eaSRichard Henderson static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn, 298298cd9ca7SRichard Henderson const DisasInsn *di) 298398cd9ca7SRichard Henderson { 298498cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 298598cd9ca7SRichard Henderson unsigned link = extract32(insn, 21, 5); 298698cd9ca7SRichard Henderson target_long disp = assemble_17(insn); 298798cd9ca7SRichard Henderson 298898cd9ca7SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n); 298998cd9ca7SRichard Henderson } 299098cd9ca7SRichard Henderson 2991869051eaSRichard Henderson static DisasJumpType trans_bl_long(DisasContext *ctx, uint32_t insn, 299298cd9ca7SRichard Henderson const DisasInsn *di) 299398cd9ca7SRichard Henderson { 299498cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 299598cd9ca7SRichard Henderson target_long disp = assemble_22(insn); 299698cd9ca7SRichard Henderson 299798cd9ca7SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n); 299898cd9ca7SRichard Henderson } 299998cd9ca7SRichard Henderson 3000869051eaSRichard Henderson static DisasJumpType trans_blr(DisasContext *ctx, uint32_t insn, 300198cd9ca7SRichard Henderson const DisasInsn *di) 300298cd9ca7SRichard Henderson { 300398cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 300498cd9ca7SRichard Henderson unsigned rx = extract32(insn, 16, 5); 300598cd9ca7SRichard Henderson unsigned link = extract32(insn, 21, 5); 300698cd9ca7SRichard Henderson TCGv tmp = get_temp(ctx); 300798cd9ca7SRichard Henderson 300898cd9ca7SRichard Henderson tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3); 300998cd9ca7SRichard Henderson tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8); 301098cd9ca7SRichard Henderson return do_ibranch(ctx, tmp, link, n); 301198cd9ca7SRichard Henderson } 301298cd9ca7SRichard Henderson 3013869051eaSRichard Henderson static DisasJumpType trans_bv(DisasContext *ctx, uint32_t insn, 301498cd9ca7SRichard Henderson const DisasInsn *di) 301598cd9ca7SRichard Henderson { 301698cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 301798cd9ca7SRichard Henderson unsigned rx = extract32(insn, 16, 5); 301898cd9ca7SRichard Henderson unsigned rb = extract32(insn, 21, 5); 301998cd9ca7SRichard Henderson TCGv dest; 302098cd9ca7SRichard Henderson 302198cd9ca7SRichard Henderson if (rx == 0) { 302298cd9ca7SRichard Henderson dest = load_gpr(ctx, rb); 302398cd9ca7SRichard Henderson } else { 302498cd9ca7SRichard Henderson dest = get_temp(ctx); 302598cd9ca7SRichard Henderson tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3); 302698cd9ca7SRichard Henderson tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb)); 302798cd9ca7SRichard Henderson } 302898cd9ca7SRichard Henderson return do_ibranch(ctx, dest, 0, n); 302998cd9ca7SRichard Henderson } 303098cd9ca7SRichard Henderson 3031869051eaSRichard Henderson static DisasJumpType trans_bve(DisasContext *ctx, uint32_t insn, 303298cd9ca7SRichard Henderson const DisasInsn *di) 303398cd9ca7SRichard Henderson { 303498cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 303598cd9ca7SRichard Henderson unsigned rb = extract32(insn, 21, 5); 303698cd9ca7SRichard Henderson unsigned link = extract32(insn, 13, 1) ? 2 : 0; 303798cd9ca7SRichard Henderson 303898cd9ca7SRichard Henderson return do_ibranch(ctx, load_gpr(ctx, rb), link, n); 303998cd9ca7SRichard Henderson } 304098cd9ca7SRichard Henderson 304198cd9ca7SRichard Henderson static const DisasInsn table_branch[] = { 304298cd9ca7SRichard Henderson { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */ 304398cd9ca7SRichard Henderson { 0xe800a000u, 0xfc00e000u, trans_bl_long }, 304498cd9ca7SRichard Henderson { 0xe8004000u, 0xfc00fffdu, trans_blr }, 304598cd9ca7SRichard Henderson { 0xe800c000u, 0xfc00fffdu, trans_bv }, 304698cd9ca7SRichard Henderson { 0xe800d000u, 0xfc00dffcu, trans_bve }, 304798cd9ca7SRichard Henderson }; 304898cd9ca7SRichard Henderson 3049869051eaSRichard Henderson static DisasJumpType trans_fop_wew_0c(DisasContext *ctx, uint32_t insn, 3050ebe9383cSRichard Henderson const DisasInsn *di) 3051ebe9383cSRichard Henderson { 3052ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3053ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3054eff235ebSPaolo Bonzini return do_fop_wew(ctx, rt, ra, di->f.wew); 3055ebe9383cSRichard Henderson } 3056ebe9383cSRichard Henderson 3057869051eaSRichard Henderson static DisasJumpType trans_fop_wew_0e(DisasContext *ctx, uint32_t insn, 3058ebe9383cSRichard Henderson const DisasInsn *di) 3059ebe9383cSRichard Henderson { 3060ebe9383cSRichard Henderson unsigned rt = assemble_rt64(insn); 3061ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 3062eff235ebSPaolo Bonzini return do_fop_wew(ctx, rt, ra, di->f.wew); 3063ebe9383cSRichard Henderson } 3064ebe9383cSRichard Henderson 3065869051eaSRichard Henderson static DisasJumpType trans_fop_ded(DisasContext *ctx, uint32_t insn, 3066ebe9383cSRichard Henderson const DisasInsn *di) 3067ebe9383cSRichard Henderson { 3068ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3069ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3070eff235ebSPaolo Bonzini return do_fop_ded(ctx, rt, ra, di->f.ded); 3071ebe9383cSRichard Henderson } 3072ebe9383cSRichard Henderson 3073869051eaSRichard Henderson static DisasJumpType trans_fop_wed_0c(DisasContext *ctx, uint32_t insn, 3074ebe9383cSRichard Henderson const DisasInsn *di) 3075ebe9383cSRichard Henderson { 3076ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3077ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3078eff235ebSPaolo Bonzini return do_fop_wed(ctx, rt, ra, di->f.wed); 3079ebe9383cSRichard Henderson } 3080ebe9383cSRichard Henderson 3081869051eaSRichard Henderson static DisasJumpType trans_fop_wed_0e(DisasContext *ctx, uint32_t insn, 3082ebe9383cSRichard Henderson const DisasInsn *di) 3083ebe9383cSRichard Henderson { 3084ebe9383cSRichard Henderson unsigned rt = assemble_rt64(insn); 3085ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3086eff235ebSPaolo Bonzini return do_fop_wed(ctx, rt, ra, di->f.wed); 3087ebe9383cSRichard Henderson } 3088ebe9383cSRichard Henderson 3089869051eaSRichard Henderson static DisasJumpType trans_fop_dew_0c(DisasContext *ctx, uint32_t insn, 3090ebe9383cSRichard Henderson const DisasInsn *di) 3091ebe9383cSRichard Henderson { 3092ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3093ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3094eff235ebSPaolo Bonzini return do_fop_dew(ctx, rt, ra, di->f.dew); 3095ebe9383cSRichard Henderson } 3096ebe9383cSRichard Henderson 3097869051eaSRichard Henderson static DisasJumpType trans_fop_dew_0e(DisasContext *ctx, uint32_t insn, 3098ebe9383cSRichard Henderson const DisasInsn *di) 3099ebe9383cSRichard Henderson { 3100ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3101ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 3102eff235ebSPaolo Bonzini return do_fop_dew(ctx, rt, ra, di->f.dew); 3103ebe9383cSRichard Henderson } 3104ebe9383cSRichard Henderson 3105869051eaSRichard Henderson static DisasJumpType trans_fop_weww_0c(DisasContext *ctx, uint32_t insn, 3106ebe9383cSRichard Henderson const DisasInsn *di) 3107ebe9383cSRichard Henderson { 3108ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3109ebe9383cSRichard Henderson unsigned rb = extract32(insn, 16, 5); 3110ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3111eff235ebSPaolo Bonzini return do_fop_weww(ctx, rt, ra, rb, di->f.weww); 3112ebe9383cSRichard Henderson } 3113ebe9383cSRichard Henderson 3114869051eaSRichard Henderson static DisasJumpType trans_fop_weww_0e(DisasContext *ctx, uint32_t insn, 3115ebe9383cSRichard Henderson const DisasInsn *di) 3116ebe9383cSRichard Henderson { 3117ebe9383cSRichard Henderson unsigned rt = assemble_rt64(insn); 3118ebe9383cSRichard Henderson unsigned rb = assemble_rb64(insn); 3119ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 3120eff235ebSPaolo Bonzini return do_fop_weww(ctx, rt, ra, rb, di->f.weww); 3121ebe9383cSRichard Henderson } 3122ebe9383cSRichard Henderson 3123869051eaSRichard Henderson static DisasJumpType trans_fop_dedd(DisasContext *ctx, uint32_t insn, 3124ebe9383cSRichard Henderson const DisasInsn *di) 3125ebe9383cSRichard Henderson { 3126ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3127ebe9383cSRichard Henderson unsigned rb = extract32(insn, 16, 5); 3128ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3129eff235ebSPaolo Bonzini return do_fop_dedd(ctx, rt, ra, rb, di->f.dedd); 3130ebe9383cSRichard Henderson } 3131ebe9383cSRichard Henderson 3132ebe9383cSRichard Henderson static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3133ebe9383cSRichard Henderson { 3134ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3135ebe9383cSRichard Henderson } 3136ebe9383cSRichard Henderson 3137ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3138ebe9383cSRichard Henderson { 3139ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 3140ebe9383cSRichard Henderson } 3141ebe9383cSRichard Henderson 3142ebe9383cSRichard Henderson static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3143ebe9383cSRichard Henderson { 3144ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 3145ebe9383cSRichard Henderson } 3146ebe9383cSRichard Henderson 3147ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3148ebe9383cSRichard Henderson { 3149ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 3150ebe9383cSRichard Henderson } 3151ebe9383cSRichard Henderson 3152ebe9383cSRichard Henderson static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3153ebe9383cSRichard Henderson { 3154ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 3155ebe9383cSRichard Henderson } 3156ebe9383cSRichard Henderson 3157ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3158ebe9383cSRichard Henderson { 3159ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 3160ebe9383cSRichard Henderson } 3161ebe9383cSRichard Henderson 3162ebe9383cSRichard Henderson static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3163ebe9383cSRichard Henderson { 3164ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 3165ebe9383cSRichard Henderson } 3166ebe9383cSRichard Henderson 3167ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3168ebe9383cSRichard Henderson { 3169ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 3170ebe9383cSRichard Henderson } 3171ebe9383cSRichard Henderson 3172869051eaSRichard Henderson static DisasJumpType do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb, 3173ebe9383cSRichard Henderson unsigned y, unsigned c) 3174ebe9383cSRichard Henderson { 3175ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 3176ebe9383cSRichard Henderson 3177ebe9383cSRichard Henderson nullify_over(ctx); 3178ebe9383cSRichard Henderson 3179ebe9383cSRichard Henderson ta = load_frw0_i32(ra); 3180ebe9383cSRichard Henderson tb = load_frw0_i32(rb); 3181ebe9383cSRichard Henderson ty = tcg_const_i32(y); 3182ebe9383cSRichard Henderson tc = tcg_const_i32(c); 3183ebe9383cSRichard Henderson 3184ebe9383cSRichard Henderson gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc); 3185ebe9383cSRichard Henderson 3186ebe9383cSRichard Henderson tcg_temp_free_i32(ta); 3187ebe9383cSRichard Henderson tcg_temp_free_i32(tb); 3188ebe9383cSRichard Henderson tcg_temp_free_i32(ty); 3189ebe9383cSRichard Henderson tcg_temp_free_i32(tc); 3190ebe9383cSRichard Henderson 3191869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 3192ebe9383cSRichard Henderson } 3193ebe9383cSRichard Henderson 3194869051eaSRichard Henderson static DisasJumpType trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn, 3195ebe9383cSRichard Henderson const DisasInsn *di) 3196ebe9383cSRichard Henderson { 3197ebe9383cSRichard Henderson unsigned c = extract32(insn, 0, 5); 3198ebe9383cSRichard Henderson unsigned y = extract32(insn, 13, 3); 3199ebe9383cSRichard Henderson unsigned rb = extract32(insn, 16, 5); 3200ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3201ebe9383cSRichard Henderson return do_fcmp_s(ctx, ra, rb, y, c); 3202ebe9383cSRichard Henderson } 3203ebe9383cSRichard Henderson 3204869051eaSRichard Henderson static DisasJumpType trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn, 3205ebe9383cSRichard Henderson const DisasInsn *di) 3206ebe9383cSRichard Henderson { 3207ebe9383cSRichard Henderson unsigned c = extract32(insn, 0, 5); 3208ebe9383cSRichard Henderson unsigned y = extract32(insn, 13, 3); 3209ebe9383cSRichard Henderson unsigned rb = assemble_rb64(insn); 3210ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 3211ebe9383cSRichard Henderson return do_fcmp_s(ctx, ra, rb, y, c); 3212ebe9383cSRichard Henderson } 3213ebe9383cSRichard Henderson 3214869051eaSRichard Henderson static DisasJumpType trans_fcmp_d(DisasContext *ctx, uint32_t insn, 3215ebe9383cSRichard Henderson const DisasInsn *di) 3216ebe9383cSRichard Henderson { 3217ebe9383cSRichard Henderson unsigned c = extract32(insn, 0, 5); 3218ebe9383cSRichard Henderson unsigned y = extract32(insn, 13, 3); 3219ebe9383cSRichard Henderson unsigned rb = extract32(insn, 16, 5); 3220ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3221ebe9383cSRichard Henderson TCGv_i64 ta, tb; 3222ebe9383cSRichard Henderson TCGv_i32 tc, ty; 3223ebe9383cSRichard Henderson 3224ebe9383cSRichard Henderson nullify_over(ctx); 3225ebe9383cSRichard Henderson 3226ebe9383cSRichard Henderson ta = load_frd0(ra); 3227ebe9383cSRichard Henderson tb = load_frd0(rb); 3228ebe9383cSRichard Henderson ty = tcg_const_i32(y); 3229ebe9383cSRichard Henderson tc = tcg_const_i32(c); 3230ebe9383cSRichard Henderson 3231ebe9383cSRichard Henderson gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc); 3232ebe9383cSRichard Henderson 3233ebe9383cSRichard Henderson tcg_temp_free_i64(ta); 3234ebe9383cSRichard Henderson tcg_temp_free_i64(tb); 3235ebe9383cSRichard Henderson tcg_temp_free_i32(ty); 3236ebe9383cSRichard Henderson tcg_temp_free_i32(tc); 3237ebe9383cSRichard Henderson 3238869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 3239ebe9383cSRichard Henderson } 3240ebe9383cSRichard Henderson 3241869051eaSRichard Henderson static DisasJumpType trans_ftest_t(DisasContext *ctx, uint32_t insn, 3242ebe9383cSRichard Henderson const DisasInsn *di) 3243ebe9383cSRichard Henderson { 3244ebe9383cSRichard Henderson unsigned y = extract32(insn, 13, 3); 3245ebe9383cSRichard Henderson unsigned cbit = (y ^ 1) - 1; 3246ebe9383cSRichard Henderson TCGv t; 3247ebe9383cSRichard Henderson 3248ebe9383cSRichard Henderson nullify_over(ctx); 3249ebe9383cSRichard Henderson 3250ebe9383cSRichard Henderson t = tcg_temp_new(); 3251ebe9383cSRichard Henderson tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow)); 3252ebe9383cSRichard Henderson tcg_gen_extract_tl(t, t, 21 - cbit, 1); 3253ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 3254ebe9383cSRichard Henderson tcg_temp_free(t); 3255ebe9383cSRichard Henderson 3256869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 3257ebe9383cSRichard Henderson } 3258ebe9383cSRichard Henderson 3259869051eaSRichard Henderson static DisasJumpType trans_ftest_q(DisasContext *ctx, uint32_t insn, 3260ebe9383cSRichard Henderson const DisasInsn *di) 3261ebe9383cSRichard Henderson { 3262ebe9383cSRichard Henderson unsigned c = extract32(insn, 0, 5); 3263ebe9383cSRichard Henderson int mask; 3264ebe9383cSRichard Henderson bool inv = false; 3265ebe9383cSRichard Henderson TCGv t; 3266ebe9383cSRichard Henderson 3267ebe9383cSRichard Henderson nullify_over(ctx); 3268ebe9383cSRichard Henderson 3269ebe9383cSRichard Henderson t = tcg_temp_new(); 3270ebe9383cSRichard Henderson tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow)); 3271ebe9383cSRichard Henderson 3272ebe9383cSRichard Henderson switch (c) { 3273ebe9383cSRichard Henderson case 0: /* simple */ 3274ebe9383cSRichard Henderson tcg_gen_andi_tl(t, t, 0x4000000); 3275ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 3276ebe9383cSRichard Henderson goto done; 3277ebe9383cSRichard Henderson case 2: /* rej */ 3278ebe9383cSRichard Henderson inv = true; 3279ebe9383cSRichard Henderson /* fallthru */ 3280ebe9383cSRichard Henderson case 1: /* acc */ 3281ebe9383cSRichard Henderson mask = 0x43ff800; 3282ebe9383cSRichard Henderson break; 3283ebe9383cSRichard Henderson case 6: /* rej8 */ 3284ebe9383cSRichard Henderson inv = true; 3285ebe9383cSRichard Henderson /* fallthru */ 3286ebe9383cSRichard Henderson case 5: /* acc8 */ 3287ebe9383cSRichard Henderson mask = 0x43f8000; 3288ebe9383cSRichard Henderson break; 3289ebe9383cSRichard Henderson case 9: /* acc6 */ 3290ebe9383cSRichard Henderson mask = 0x43e0000; 3291ebe9383cSRichard Henderson break; 3292ebe9383cSRichard Henderson case 13: /* acc4 */ 3293ebe9383cSRichard Henderson mask = 0x4380000; 3294ebe9383cSRichard Henderson break; 3295ebe9383cSRichard Henderson case 17: /* acc2 */ 3296ebe9383cSRichard Henderson mask = 0x4200000; 3297ebe9383cSRichard Henderson break; 3298ebe9383cSRichard Henderson default: 3299ebe9383cSRichard Henderson return gen_illegal(ctx); 3300ebe9383cSRichard Henderson } 3301ebe9383cSRichard Henderson if (inv) { 3302ebe9383cSRichard Henderson TCGv c = load_const(ctx, mask); 3303ebe9383cSRichard Henderson tcg_gen_or_tl(t, t, c); 3304ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 3305ebe9383cSRichard Henderson } else { 3306ebe9383cSRichard Henderson tcg_gen_andi_tl(t, t, mask); 3307ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 3308ebe9383cSRichard Henderson } 3309ebe9383cSRichard Henderson done: 3310869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 3311ebe9383cSRichard Henderson } 3312ebe9383cSRichard Henderson 3313869051eaSRichard Henderson static DisasJumpType trans_xmpyu(DisasContext *ctx, uint32_t insn, 3314ebe9383cSRichard Henderson const DisasInsn *di) 3315ebe9383cSRichard Henderson { 3316ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3317ebe9383cSRichard Henderson unsigned rb = assemble_rb64(insn); 3318ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 3319ebe9383cSRichard Henderson TCGv_i64 a, b; 3320ebe9383cSRichard Henderson 3321ebe9383cSRichard Henderson nullify_over(ctx); 3322ebe9383cSRichard Henderson 3323ebe9383cSRichard Henderson a = load_frw0_i64(ra); 3324ebe9383cSRichard Henderson b = load_frw0_i64(rb); 3325ebe9383cSRichard Henderson tcg_gen_mul_i64(a, a, b); 3326ebe9383cSRichard Henderson save_frd(rt, a); 3327ebe9383cSRichard Henderson tcg_temp_free_i64(a); 3328ebe9383cSRichard Henderson tcg_temp_free_i64(b); 3329ebe9383cSRichard Henderson 3330869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 3331ebe9383cSRichard Henderson } 3332ebe9383cSRichard Henderson 3333eff235ebSPaolo Bonzini #define FOP_DED trans_fop_ded, .f.ded 3334eff235ebSPaolo Bonzini #define FOP_DEDD trans_fop_dedd, .f.dedd 3335ebe9383cSRichard Henderson 3336eff235ebSPaolo Bonzini #define FOP_WEW trans_fop_wew_0c, .f.wew 3337eff235ebSPaolo Bonzini #define FOP_DEW trans_fop_dew_0c, .f.dew 3338eff235ebSPaolo Bonzini #define FOP_WED trans_fop_wed_0c, .f.wed 3339eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0c, .f.weww 3340ebe9383cSRichard Henderson 3341ebe9383cSRichard Henderson static const DisasInsn table_float_0c[] = { 3342ebe9383cSRichard Henderson /* floating point class zero */ 3343ebe9383cSRichard Henderson { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s }, 3344ebe9383cSRichard Henderson { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s }, 3345ebe9383cSRichard Henderson { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s }, 3346ebe9383cSRichard Henderson { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s }, 3347ebe9383cSRichard Henderson { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s }, 3348ebe9383cSRichard Henderson { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s }, 3349ebe9383cSRichard Henderson 3350ebe9383cSRichard Henderson { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d }, 3351ebe9383cSRichard Henderson { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d }, 3352ebe9383cSRichard Henderson { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d }, 3353ebe9383cSRichard Henderson { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d }, 3354ebe9383cSRichard Henderson { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d }, 3355ebe9383cSRichard Henderson { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d }, 3356ebe9383cSRichard Henderson 3357ebe9383cSRichard Henderson /* floating point class three */ 3358ebe9383cSRichard Henderson { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s }, 3359ebe9383cSRichard Henderson { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s }, 3360ebe9383cSRichard Henderson { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s }, 3361ebe9383cSRichard Henderson { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s }, 3362ebe9383cSRichard Henderson 3363ebe9383cSRichard Henderson { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d }, 3364ebe9383cSRichard Henderson { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d }, 3365ebe9383cSRichard Henderson { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d }, 3366ebe9383cSRichard Henderson { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d }, 3367ebe9383cSRichard Henderson 3368ebe9383cSRichard Henderson /* floating point class one */ 3369ebe9383cSRichard Henderson /* float/float */ 3370ebe9383cSRichard Henderson { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s }, 3371ebe9383cSRichard Henderson { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d }, 3372ebe9383cSRichard Henderson /* int/float */ 3373ebe9383cSRichard Henderson { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s }, 3374ebe9383cSRichard Henderson { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s }, 3375ebe9383cSRichard Henderson { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d }, 3376ebe9383cSRichard Henderson { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d }, 3377ebe9383cSRichard Henderson /* float/int */ 3378ebe9383cSRichard Henderson { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w }, 3379ebe9383cSRichard Henderson { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w }, 3380ebe9383cSRichard Henderson { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw }, 3381ebe9383cSRichard Henderson { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw }, 3382ebe9383cSRichard Henderson /* float/int truncate */ 3383ebe9383cSRichard Henderson { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w }, 3384ebe9383cSRichard Henderson { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w }, 3385ebe9383cSRichard Henderson { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw }, 3386ebe9383cSRichard Henderson { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw }, 3387ebe9383cSRichard Henderson /* uint/float */ 3388ebe9383cSRichard Henderson { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s }, 3389ebe9383cSRichard Henderson { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s }, 3390ebe9383cSRichard Henderson { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d }, 3391ebe9383cSRichard Henderson { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d }, 3392ebe9383cSRichard Henderson /* float/uint */ 3393ebe9383cSRichard Henderson { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw }, 3394ebe9383cSRichard Henderson { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw }, 3395ebe9383cSRichard Henderson { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw }, 3396ebe9383cSRichard Henderson { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw }, 3397ebe9383cSRichard Henderson /* float/uint truncate */ 3398ebe9383cSRichard Henderson { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw }, 3399ebe9383cSRichard Henderson { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw }, 3400ebe9383cSRichard Henderson { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw }, 3401ebe9383cSRichard Henderson { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw }, 3402ebe9383cSRichard Henderson 3403ebe9383cSRichard Henderson /* floating point class two */ 3404ebe9383cSRichard Henderson { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c }, 3405ebe9383cSRichard Henderson { 0x30000c00, 0xfc001fe0, trans_fcmp_d }, 3406ebe9383cSRichard Henderson { 0x30002420, 0xffffffe0, trans_ftest_q }, 3407ebe9383cSRichard Henderson { 0x30000420, 0xffff1fff, trans_ftest_t }, 3408ebe9383cSRichard Henderson 3409ebe9383cSRichard Henderson /* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0. 3410ebe9383cSRichard Henderson This is machine/revision == 0, which is reserved for simulator. */ 3411ebe9383cSRichard Henderson { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s }, 3412ebe9383cSRichard Henderson }; 3413ebe9383cSRichard Henderson 3414ebe9383cSRichard Henderson #undef FOP_WEW 3415ebe9383cSRichard Henderson #undef FOP_DEW 3416ebe9383cSRichard Henderson #undef FOP_WED 3417ebe9383cSRichard Henderson #undef FOP_WEWW 3418eff235ebSPaolo Bonzini #define FOP_WEW trans_fop_wew_0e, .f.wew 3419eff235ebSPaolo Bonzini #define FOP_DEW trans_fop_dew_0e, .f.dew 3420eff235ebSPaolo Bonzini #define FOP_WED trans_fop_wed_0e, .f.wed 3421eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0e, .f.weww 3422ebe9383cSRichard Henderson 3423ebe9383cSRichard Henderson static const DisasInsn table_float_0e[] = { 3424ebe9383cSRichard Henderson /* floating point class zero */ 3425ebe9383cSRichard Henderson { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s }, 3426ebe9383cSRichard Henderson { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s }, 3427ebe9383cSRichard Henderson { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s }, 3428ebe9383cSRichard Henderson { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s }, 3429ebe9383cSRichard Henderson { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s }, 3430ebe9383cSRichard Henderson { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s }, 3431ebe9383cSRichard Henderson 3432ebe9383cSRichard Henderson { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d }, 3433ebe9383cSRichard Henderson { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d }, 3434ebe9383cSRichard Henderson { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d }, 3435ebe9383cSRichard Henderson { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d }, 3436ebe9383cSRichard Henderson { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d }, 3437ebe9383cSRichard Henderson { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d }, 3438ebe9383cSRichard Henderson 3439ebe9383cSRichard Henderson /* floating point class three */ 3440ebe9383cSRichard Henderson { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s }, 3441ebe9383cSRichard Henderson { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s }, 3442ebe9383cSRichard Henderson { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s }, 3443ebe9383cSRichard Henderson { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s }, 3444ebe9383cSRichard Henderson 3445ebe9383cSRichard Henderson { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d }, 3446ebe9383cSRichard Henderson { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d }, 3447ebe9383cSRichard Henderson { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d }, 3448ebe9383cSRichard Henderson { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d }, 3449ebe9383cSRichard Henderson 3450ebe9383cSRichard Henderson { 0x38004700, 0xfc00ef60, trans_xmpyu }, 3451ebe9383cSRichard Henderson 3452ebe9383cSRichard Henderson /* floating point class one */ 3453ebe9383cSRichard Henderson /* float/float */ 3454ebe9383cSRichard Henderson { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s }, 3455ebe9383cSRichard Henderson { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d }, 3456ebe9383cSRichard Henderson /* int/float */ 3457ebe9383cSRichard Henderson { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s }, 3458ebe9383cSRichard Henderson { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s }, 3459ebe9383cSRichard Henderson { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d }, 3460ebe9383cSRichard Henderson { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d }, 3461ebe9383cSRichard Henderson /* float/int */ 3462ebe9383cSRichard Henderson { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w }, 3463ebe9383cSRichard Henderson { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w }, 3464ebe9383cSRichard Henderson { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw }, 3465ebe9383cSRichard Henderson { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw }, 3466ebe9383cSRichard Henderson /* float/int truncate */ 3467ebe9383cSRichard Henderson { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w }, 3468ebe9383cSRichard Henderson { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w }, 3469ebe9383cSRichard Henderson { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw }, 3470ebe9383cSRichard Henderson { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw }, 3471ebe9383cSRichard Henderson /* uint/float */ 3472ebe9383cSRichard Henderson { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s }, 3473ebe9383cSRichard Henderson { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s }, 3474ebe9383cSRichard Henderson { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d }, 3475ebe9383cSRichard Henderson { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d }, 3476ebe9383cSRichard Henderson /* float/uint */ 3477ebe9383cSRichard Henderson { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw }, 3478ebe9383cSRichard Henderson { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw }, 3479ebe9383cSRichard Henderson { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw }, 3480ebe9383cSRichard Henderson { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw }, 3481ebe9383cSRichard Henderson /* float/uint truncate */ 3482ebe9383cSRichard Henderson { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw }, 3483ebe9383cSRichard Henderson { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw }, 3484ebe9383cSRichard Henderson { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw }, 3485ebe9383cSRichard Henderson { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw }, 3486ebe9383cSRichard Henderson 3487ebe9383cSRichard Henderson /* floating point class two */ 3488ebe9383cSRichard Henderson { 0x38000400, 0xfc000f60, trans_fcmp_s_0e }, 3489ebe9383cSRichard Henderson { 0x38000c00, 0xfc001fe0, trans_fcmp_d }, 3490ebe9383cSRichard Henderson }; 3491ebe9383cSRichard Henderson 3492ebe9383cSRichard Henderson #undef FOP_WEW 3493ebe9383cSRichard Henderson #undef FOP_DEW 3494ebe9383cSRichard Henderson #undef FOP_WED 3495ebe9383cSRichard Henderson #undef FOP_WEWW 3496ebe9383cSRichard Henderson #undef FOP_DED 3497ebe9383cSRichard Henderson #undef FOP_DEDD 3498ebe9383cSRichard Henderson 3499ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 3500ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 3501ebe9383cSRichard Henderson { 3502ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 3503ebe9383cSRichard Henderson } 3504ebe9383cSRichard Henderson 3505869051eaSRichard Henderson static DisasJumpType trans_fmpyadd(DisasContext *ctx, 3506869051eaSRichard Henderson uint32_t insn, bool is_sub) 3507ebe9383cSRichard Henderson { 3508ebe9383cSRichard Henderson unsigned tm = extract32(insn, 0, 5); 3509ebe9383cSRichard Henderson unsigned f = extract32(insn, 5, 1); 3510ebe9383cSRichard Henderson unsigned ra = extract32(insn, 6, 5); 3511ebe9383cSRichard Henderson unsigned ta = extract32(insn, 11, 5); 3512ebe9383cSRichard Henderson unsigned rm2 = extract32(insn, 16, 5); 3513ebe9383cSRichard Henderson unsigned rm1 = extract32(insn, 21, 5); 3514ebe9383cSRichard Henderson 3515ebe9383cSRichard Henderson nullify_over(ctx); 3516ebe9383cSRichard Henderson 3517ebe9383cSRichard Henderson /* Independent multiply & add/sub, with undefined behaviour 3518ebe9383cSRichard Henderson if outputs overlap inputs. */ 3519ebe9383cSRichard Henderson if (f == 0) { 3520ebe9383cSRichard Henderson tm = fmpyadd_s_reg(tm); 3521ebe9383cSRichard Henderson ra = fmpyadd_s_reg(ra); 3522ebe9383cSRichard Henderson ta = fmpyadd_s_reg(ta); 3523ebe9383cSRichard Henderson rm2 = fmpyadd_s_reg(rm2); 3524ebe9383cSRichard Henderson rm1 = fmpyadd_s_reg(rm1); 3525ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 3526ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 3527ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 3528ebe9383cSRichard Henderson } else { 3529ebe9383cSRichard Henderson do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d); 3530ebe9383cSRichard Henderson do_fop_dedd(ctx, ta, ta, ra, 3531ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 3532ebe9383cSRichard Henderson } 3533ebe9383cSRichard Henderson 3534869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 3535ebe9383cSRichard Henderson } 3536ebe9383cSRichard Henderson 3537869051eaSRichard Henderson static DisasJumpType trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn, 3538ebe9383cSRichard Henderson const DisasInsn *di) 3539ebe9383cSRichard Henderson { 3540ebe9383cSRichard Henderson unsigned rt = assemble_rt64(insn); 3541ebe9383cSRichard Henderson unsigned neg = extract32(insn, 5, 1); 3542ebe9383cSRichard Henderson unsigned rm1 = assemble_ra64(insn); 3543ebe9383cSRichard Henderson unsigned rm2 = assemble_rb64(insn); 3544ebe9383cSRichard Henderson unsigned ra3 = assemble_rc64(insn); 3545ebe9383cSRichard Henderson TCGv_i32 a, b, c; 3546ebe9383cSRichard Henderson 3547ebe9383cSRichard Henderson nullify_over(ctx); 3548ebe9383cSRichard Henderson a = load_frw0_i32(rm1); 3549ebe9383cSRichard Henderson b = load_frw0_i32(rm2); 3550ebe9383cSRichard Henderson c = load_frw0_i32(ra3); 3551ebe9383cSRichard Henderson 3552ebe9383cSRichard Henderson if (neg) { 3553ebe9383cSRichard Henderson gen_helper_fmpynfadd_s(a, cpu_env, a, b, c); 3554ebe9383cSRichard Henderson } else { 3555ebe9383cSRichard Henderson gen_helper_fmpyfadd_s(a, cpu_env, a, b, c); 3556ebe9383cSRichard Henderson } 3557ebe9383cSRichard Henderson 3558ebe9383cSRichard Henderson tcg_temp_free_i32(b); 3559ebe9383cSRichard Henderson tcg_temp_free_i32(c); 3560ebe9383cSRichard Henderson save_frw_i32(rt, a); 3561ebe9383cSRichard Henderson tcg_temp_free_i32(a); 3562869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 3563ebe9383cSRichard Henderson } 3564ebe9383cSRichard Henderson 3565869051eaSRichard Henderson static DisasJumpType trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn, 3566ebe9383cSRichard Henderson const DisasInsn *di) 3567ebe9383cSRichard Henderson { 3568ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3569ebe9383cSRichard Henderson unsigned neg = extract32(insn, 5, 1); 3570ebe9383cSRichard Henderson unsigned rm1 = extract32(insn, 21, 5); 3571ebe9383cSRichard Henderson unsigned rm2 = extract32(insn, 16, 5); 3572ebe9383cSRichard Henderson unsigned ra3 = assemble_rc64(insn); 3573ebe9383cSRichard Henderson TCGv_i64 a, b, c; 3574ebe9383cSRichard Henderson 3575ebe9383cSRichard Henderson nullify_over(ctx); 3576ebe9383cSRichard Henderson a = load_frd0(rm1); 3577ebe9383cSRichard Henderson b = load_frd0(rm2); 3578ebe9383cSRichard Henderson c = load_frd0(ra3); 3579ebe9383cSRichard Henderson 3580ebe9383cSRichard Henderson if (neg) { 3581ebe9383cSRichard Henderson gen_helper_fmpynfadd_d(a, cpu_env, a, b, c); 3582ebe9383cSRichard Henderson } else { 3583ebe9383cSRichard Henderson gen_helper_fmpyfadd_d(a, cpu_env, a, b, c); 3584ebe9383cSRichard Henderson } 3585ebe9383cSRichard Henderson 3586ebe9383cSRichard Henderson tcg_temp_free_i64(b); 3587ebe9383cSRichard Henderson tcg_temp_free_i64(c); 3588ebe9383cSRichard Henderson save_frd(rt, a); 3589ebe9383cSRichard Henderson tcg_temp_free_i64(a); 3590869051eaSRichard Henderson return nullify_end(ctx, DISAS_NEXT); 3591ebe9383cSRichard Henderson } 3592ebe9383cSRichard Henderson 3593ebe9383cSRichard Henderson static const DisasInsn table_fp_fused[] = { 3594ebe9383cSRichard Henderson { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s }, 3595ebe9383cSRichard Henderson { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d } 3596ebe9383cSRichard Henderson }; 3597ebe9383cSRichard Henderson 3598869051eaSRichard Henderson static DisasJumpType translate_table_int(DisasContext *ctx, uint32_t insn, 359961766fe9SRichard Henderson const DisasInsn table[], size_t n) 360061766fe9SRichard Henderson { 360161766fe9SRichard Henderson size_t i; 360261766fe9SRichard Henderson for (i = 0; i < n; ++i) { 360361766fe9SRichard Henderson if ((insn & table[i].mask) == table[i].insn) { 360461766fe9SRichard Henderson return table[i].trans(ctx, insn, &table[i]); 360561766fe9SRichard Henderson } 360661766fe9SRichard Henderson } 360761766fe9SRichard Henderson return gen_illegal(ctx); 360861766fe9SRichard Henderson } 360961766fe9SRichard Henderson 361061766fe9SRichard Henderson #define translate_table(ctx, insn, table) \ 361161766fe9SRichard Henderson translate_table_int(ctx, insn, table, ARRAY_SIZE(table)) 361261766fe9SRichard Henderson 3613869051eaSRichard Henderson static DisasJumpType translate_one(DisasContext *ctx, uint32_t insn) 361461766fe9SRichard Henderson { 361561766fe9SRichard Henderson uint32_t opc = extract32(insn, 26, 6); 361661766fe9SRichard Henderson 361761766fe9SRichard Henderson switch (opc) { 361898a9cb79SRichard Henderson case 0x00: /* system op */ 361998a9cb79SRichard Henderson return translate_table(ctx, insn, table_system); 362098a9cb79SRichard Henderson case 0x01: 362198a9cb79SRichard Henderson return translate_table(ctx, insn, table_mem_mgmt); 3622b2167459SRichard Henderson case 0x02: 3623b2167459SRichard Henderson return translate_table(ctx, insn, table_arith_log); 362496d6407fSRichard Henderson case 0x03: 362596d6407fSRichard Henderson return translate_table(ctx, insn, table_index_mem); 3626ebe9383cSRichard Henderson case 0x06: 3627ebe9383cSRichard Henderson return trans_fmpyadd(ctx, insn, false); 3628b2167459SRichard Henderson case 0x08: 3629b2167459SRichard Henderson return trans_ldil(ctx, insn); 363096d6407fSRichard Henderson case 0x09: 363196d6407fSRichard Henderson return trans_copr_w(ctx, insn); 3632b2167459SRichard Henderson case 0x0A: 3633b2167459SRichard Henderson return trans_addil(ctx, insn); 363496d6407fSRichard Henderson case 0x0B: 363596d6407fSRichard Henderson return trans_copr_dw(ctx, insn); 3636ebe9383cSRichard Henderson case 0x0C: 3637ebe9383cSRichard Henderson return translate_table(ctx, insn, table_float_0c); 3638b2167459SRichard Henderson case 0x0D: 3639b2167459SRichard Henderson return trans_ldo(ctx, insn); 3640ebe9383cSRichard Henderson case 0x0E: 3641ebe9383cSRichard Henderson return translate_table(ctx, insn, table_float_0e); 364296d6407fSRichard Henderson 364396d6407fSRichard Henderson case 0x10: 364496d6407fSRichard Henderson return trans_load(ctx, insn, false, MO_UB); 364596d6407fSRichard Henderson case 0x11: 364696d6407fSRichard Henderson return trans_load(ctx, insn, false, MO_TEUW); 364796d6407fSRichard Henderson case 0x12: 364896d6407fSRichard Henderson return trans_load(ctx, insn, false, MO_TEUL); 364996d6407fSRichard Henderson case 0x13: 365096d6407fSRichard Henderson return trans_load(ctx, insn, true, MO_TEUL); 365196d6407fSRichard Henderson case 0x16: 365296d6407fSRichard Henderson return trans_fload_mod(ctx, insn); 365396d6407fSRichard Henderson case 0x17: 365496d6407fSRichard Henderson return trans_load_w(ctx, insn); 365596d6407fSRichard Henderson case 0x18: 365696d6407fSRichard Henderson return trans_store(ctx, insn, false, MO_UB); 365796d6407fSRichard Henderson case 0x19: 365896d6407fSRichard Henderson return trans_store(ctx, insn, false, MO_TEUW); 365996d6407fSRichard Henderson case 0x1A: 366096d6407fSRichard Henderson return trans_store(ctx, insn, false, MO_TEUL); 366196d6407fSRichard Henderson case 0x1B: 366296d6407fSRichard Henderson return trans_store(ctx, insn, true, MO_TEUL); 366396d6407fSRichard Henderson case 0x1E: 366496d6407fSRichard Henderson return trans_fstore_mod(ctx, insn); 366596d6407fSRichard Henderson case 0x1F: 366696d6407fSRichard Henderson return trans_store_w(ctx, insn); 366796d6407fSRichard Henderson 366898cd9ca7SRichard Henderson case 0x20: 366998cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, false, false); 367098cd9ca7SRichard Henderson case 0x21: 367198cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, true, false); 367298cd9ca7SRichard Henderson case 0x22: 367398cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, false, false); 367498cd9ca7SRichard Henderson case 0x23: 367598cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, true, false); 3676b2167459SRichard Henderson case 0x24: 3677b2167459SRichard Henderson return trans_cmpiclr(ctx, insn); 3678b2167459SRichard Henderson case 0x25: 3679b2167459SRichard Henderson return trans_subi(ctx, insn); 3680ebe9383cSRichard Henderson case 0x26: 3681ebe9383cSRichard Henderson return trans_fmpyadd(ctx, insn, true); 368298cd9ca7SRichard Henderson case 0x27: 368398cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, false, true); 368498cd9ca7SRichard Henderson case 0x28: 368598cd9ca7SRichard Henderson return trans_addb(ctx, insn, true, false); 368698cd9ca7SRichard Henderson case 0x29: 368798cd9ca7SRichard Henderson return trans_addb(ctx, insn, true, true); 368898cd9ca7SRichard Henderson case 0x2A: 368998cd9ca7SRichard Henderson return trans_addb(ctx, insn, false, false); 369098cd9ca7SRichard Henderson case 0x2B: 369198cd9ca7SRichard Henderson return trans_addb(ctx, insn, false, true); 3692b2167459SRichard Henderson case 0x2C: 3693b2167459SRichard Henderson case 0x2D: 3694b2167459SRichard Henderson return trans_addi(ctx, insn); 3695ebe9383cSRichard Henderson case 0x2E: 3696ebe9383cSRichard Henderson return translate_table(ctx, insn, table_fp_fused); 369798cd9ca7SRichard Henderson case 0x2F: 369898cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, false, true); 369996d6407fSRichard Henderson 370098cd9ca7SRichard Henderson case 0x30: 370198cd9ca7SRichard Henderson case 0x31: 370298cd9ca7SRichard Henderson return trans_bb(ctx, insn); 370398cd9ca7SRichard Henderson case 0x32: 370498cd9ca7SRichard Henderson return trans_movb(ctx, insn, false); 370598cd9ca7SRichard Henderson case 0x33: 370698cd9ca7SRichard Henderson return trans_movb(ctx, insn, true); 37070b1347d2SRichard Henderson case 0x34: 37080b1347d2SRichard Henderson return translate_table(ctx, insn, table_sh_ex); 37090b1347d2SRichard Henderson case 0x35: 37100b1347d2SRichard Henderson return translate_table(ctx, insn, table_depw); 371198cd9ca7SRichard Henderson case 0x38: 371298cd9ca7SRichard Henderson return trans_be(ctx, insn, false); 371398cd9ca7SRichard Henderson case 0x39: 371498cd9ca7SRichard Henderson return trans_be(ctx, insn, true); 371598cd9ca7SRichard Henderson case 0x3A: 371698cd9ca7SRichard Henderson return translate_table(ctx, insn, table_branch); 371796d6407fSRichard Henderson 371896d6407fSRichard Henderson case 0x04: /* spopn */ 371996d6407fSRichard Henderson case 0x05: /* diag */ 372096d6407fSRichard Henderson case 0x0F: /* product specific */ 372196d6407fSRichard Henderson break; 372296d6407fSRichard Henderson 372396d6407fSRichard Henderson case 0x07: /* unassigned */ 372496d6407fSRichard Henderson case 0x15: /* unassigned */ 372596d6407fSRichard Henderson case 0x1D: /* unassigned */ 372696d6407fSRichard Henderson case 0x37: /* unassigned */ 372796d6407fSRichard Henderson case 0x3F: /* unassigned */ 372861766fe9SRichard Henderson default: 372961766fe9SRichard Henderson break; 373061766fe9SRichard Henderson } 373161766fe9SRichard Henderson return gen_illegal(ctx); 373261766fe9SRichard Henderson } 373361766fe9SRichard Henderson 373451b061fbSRichard Henderson static int hppa_tr_init_disas_context(DisasContextBase *dcbase, 373551b061fbSRichard Henderson CPUState *cs, int max_insns) 373661766fe9SRichard Henderson { 373751b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 373851b061fbSRichard Henderson TranslationBlock *tb = ctx->base.tb; 373951b061fbSRichard Henderson int i, bound; 374061766fe9SRichard Henderson 374151b061fbSRichard Henderson ctx->cs = cs; 374251b061fbSRichard Henderson ctx->iaoq_f = tb->pc; 374351b061fbSRichard Henderson ctx->iaoq_b = tb->cs_base; 374451b061fbSRichard Henderson ctx->iaoq_n = -1; 374551b061fbSRichard Henderson TCGV_UNUSED(ctx->iaoq_n_var); 374661766fe9SRichard Henderson 374751b061fbSRichard Henderson ctx->ntemps = 0; 374851b061fbSRichard Henderson for (i = 0; i < ARRAY_SIZE(ctx->temps); ++i) { 374951b061fbSRichard Henderson TCGV_UNUSED(ctx->temps[i]); 375061766fe9SRichard Henderson } 375161766fe9SRichard Henderson 375251b061fbSRichard Henderson bound = -(tb->pc | TARGET_PAGE_MASK) / 4; 375351b061fbSRichard Henderson return MIN(max_insns, bound); 375461766fe9SRichard Henderson } 375561766fe9SRichard Henderson 375651b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 375751b061fbSRichard Henderson { 375851b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 375961766fe9SRichard Henderson 3760129e9cc3SRichard Henderson /* Seed the nullification status from PSW[N], as shown in TB->FLAGS. */ 376151b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 376251b061fbSRichard Henderson ctx->psw_n_nonzero = false; 376351b061fbSRichard Henderson if (ctx->base.tb->flags & 1) { 376451b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 376551b061fbSRichard Henderson ctx->psw_n_nonzero = true; 3766129e9cc3SRichard Henderson } 376751b061fbSRichard Henderson ctx->null_lab = NULL; 376861766fe9SRichard Henderson } 376961766fe9SRichard Henderson 377051b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 377151b061fbSRichard Henderson { 377251b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 377351b061fbSRichard Henderson 377451b061fbSRichard Henderson tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b); 377551b061fbSRichard Henderson } 377651b061fbSRichard Henderson 377751b061fbSRichard Henderson static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, 377851b061fbSRichard Henderson const CPUBreakpoint *bp) 377951b061fbSRichard Henderson { 378051b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 378151b061fbSRichard Henderson 378251b061fbSRichard Henderson ctx->base.is_jmp = gen_excp(ctx, EXCP_DEBUG); 378351b061fbSRichard Henderson ctx->base.pc_next = ctx->iaoq_f + 4; 378451b061fbSRichard Henderson return true; 378551b061fbSRichard Henderson } 378651b061fbSRichard Henderson 378751b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 378851b061fbSRichard Henderson { 378951b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 379051b061fbSRichard Henderson CPUHPPAState *env = cs->env_ptr; 379151b061fbSRichard Henderson DisasJumpType ret; 379251b061fbSRichard Henderson int i, n; 379351b061fbSRichard Henderson 379451b061fbSRichard Henderson /* Execute one insn. */ 379551b061fbSRichard Henderson if (ctx->iaoq_f < TARGET_PAGE_SIZE) { 379651b061fbSRichard Henderson ret = do_page_zero(ctx); 3797869051eaSRichard Henderson assert(ret != DISAS_NEXT); 37987ad439dfSRichard Henderson } else { 379961766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 380061766fe9SRichard Henderson the page permissions for execute. */ 380151b061fbSRichard Henderson uint32_t insn = cpu_ldl_code(env, ctx->iaoq_f); 380261766fe9SRichard Henderson 380361766fe9SRichard Henderson /* Set up the IA queue for the next insn. 380461766fe9SRichard Henderson This will be overwritten by a branch. */ 380551b061fbSRichard Henderson if (ctx->iaoq_b == -1) { 380651b061fbSRichard Henderson ctx->iaoq_n = -1; 380751b061fbSRichard Henderson ctx->iaoq_n_var = get_temp(ctx); 380851b061fbSRichard Henderson tcg_gen_addi_tl(ctx->iaoq_n_var, cpu_iaoq_b, 4); 380961766fe9SRichard Henderson } else { 381051b061fbSRichard Henderson ctx->iaoq_n = ctx->iaoq_b + 4; 381151b061fbSRichard Henderson TCGV_UNUSED(ctx->iaoq_n_var); 381261766fe9SRichard Henderson } 381361766fe9SRichard Henderson 381451b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 381551b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 3816869051eaSRichard Henderson ret = DISAS_NEXT; 3817129e9cc3SRichard Henderson } else { 381851b061fbSRichard Henderson ret = translate_one(ctx, insn); 381951b061fbSRichard Henderson assert(ctx->null_lab == NULL); 3820129e9cc3SRichard Henderson } 382161766fe9SRichard Henderson } 382261766fe9SRichard Henderson 382351b061fbSRichard Henderson /* Free any temporaries allocated. */ 382451b061fbSRichard Henderson for (i = 0, n = ctx->ntemps; i < n; ++i) { 382551b061fbSRichard Henderson tcg_temp_free(ctx->temps[i]); 382651b061fbSRichard Henderson TCGV_UNUSED(ctx->temps[i]); 382761766fe9SRichard Henderson } 382851b061fbSRichard Henderson ctx->ntemps = 0; 382961766fe9SRichard Henderson 383051b061fbSRichard Henderson /* Advance the insn queue. */ 383161766fe9SRichard Henderson /* ??? The non-linear instruction restriction is purely due to 383261766fe9SRichard Henderson the debugging dump. Otherwise we *could* follow unconditional 383361766fe9SRichard Henderson branches within the same page. */ 383451b061fbSRichard Henderson if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 383551b061fbSRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER 383651b061fbSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS) { 383751b061fbSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 383851b061fbSRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 3839869051eaSRichard Henderson ret = DISAS_NORETURN; 3840129e9cc3SRichard Henderson } else { 3841869051eaSRichard Henderson ret = DISAS_IAQ_N_STALE; 384261766fe9SRichard Henderson } 3843129e9cc3SRichard Henderson } 384451b061fbSRichard Henderson ctx->iaoq_f = ctx->iaoq_b; 384551b061fbSRichard Henderson ctx->iaoq_b = ctx->iaoq_n; 384651b061fbSRichard Henderson ctx->base.is_jmp = ret; 384761766fe9SRichard Henderson 3848869051eaSRichard Henderson if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) { 384951b061fbSRichard Henderson return; 385061766fe9SRichard Henderson } 385151b061fbSRichard Henderson if (ctx->iaoq_f == -1) { 385261766fe9SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b); 385351b061fbSRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 385451b061fbSRichard Henderson nullify_save(ctx); 385551b061fbSRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 385651b061fbSRichard Henderson } else if (ctx->iaoq_b == -1) { 385751b061fbSRichard Henderson tcg_gen_mov_tl(cpu_iaoq_b, ctx->iaoq_n_var); 385861766fe9SRichard Henderson } 385961766fe9SRichard Henderson } 386061766fe9SRichard Henderson 386151b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 386251b061fbSRichard Henderson { 386351b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 386451b061fbSRichard Henderson 386551b061fbSRichard Henderson switch (ctx->base.is_jmp) { 3866869051eaSRichard Henderson case DISAS_NORETURN: 386761766fe9SRichard Henderson break; 386851b061fbSRichard Henderson case DISAS_TOO_MANY: 3869869051eaSRichard Henderson case DISAS_IAQ_N_STALE: 387051b061fbSRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 387151b061fbSRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 387251b061fbSRichard Henderson nullify_save(ctx); 387361766fe9SRichard Henderson /* FALLTHRU */ 3874869051eaSRichard Henderson case DISAS_IAQ_N_UPDATED: 387551b061fbSRichard Henderson if (ctx->base.singlestep_enabled) { 387661766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 387761766fe9SRichard Henderson } else { 38787f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 387961766fe9SRichard Henderson } 388061766fe9SRichard Henderson break; 388161766fe9SRichard Henderson default: 388251b061fbSRichard Henderson g_assert_not_reached(); 388361766fe9SRichard Henderson } 388461766fe9SRichard Henderson 388551b061fbSRichard Henderson /* We don't actually use this during normal translation, 388651b061fbSRichard Henderson but we should interact with the generic main loop. */ 388751b061fbSRichard Henderson ctx->base.pc_next = ctx->base.tb->pc + 4 * ctx->base.num_insns; 388851b061fbSRichard Henderson } 388961766fe9SRichard Henderson 389051b061fbSRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) 389151b061fbSRichard Henderson { 389251b061fbSRichard Henderson TranslationBlock *tb = dcbase->tb; 389361766fe9SRichard Henderson 38947ad439dfSRichard Henderson switch (tb->pc) { 38957ad439dfSRichard Henderson case 0x00: 389651b061fbSRichard Henderson qemu_log("IN:\n0x00000000: (null)\n"); 38977ad439dfSRichard Henderson break; 38987ad439dfSRichard Henderson case 0xb0: 389951b061fbSRichard Henderson qemu_log("IN:\n0x000000b0: light-weight-syscall\n"); 39007ad439dfSRichard Henderson break; 39017ad439dfSRichard Henderson case 0xe0: 390251b061fbSRichard Henderson qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n"); 39037ad439dfSRichard Henderson break; 39047ad439dfSRichard Henderson case 0x100: 390551b061fbSRichard Henderson qemu_log("IN:\n0x00000100: syscall\n"); 39067ad439dfSRichard Henderson break; 39077ad439dfSRichard Henderson default: 390861766fe9SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(tb->pc)); 390961766fe9SRichard Henderson log_target_disas(cs, tb->pc, tb->size, 1); 39107ad439dfSRichard Henderson break; 39117ad439dfSRichard Henderson } 391261766fe9SRichard Henderson } 391351b061fbSRichard Henderson 391451b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 391551b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 391651b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 391751b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 391851b061fbSRichard Henderson .breakpoint_check = hppa_tr_breakpoint_check, 391951b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 392051b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 392151b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 392251b061fbSRichard Henderson }; 392351b061fbSRichard Henderson 392451b061fbSRichard Henderson void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) 392551b061fbSRichard Henderson 392651b061fbSRichard Henderson { 392751b061fbSRichard Henderson DisasContext ctx; 392851b061fbSRichard Henderson translator_loop(&hppa_tr_ops, &ctx.base, cs, tb); 392961766fe9SRichard Henderson } 393061766fe9SRichard Henderson 393161766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb, 393261766fe9SRichard Henderson target_ulong *data) 393361766fe9SRichard Henderson { 393461766fe9SRichard Henderson env->iaoq_f = data[0]; 393561766fe9SRichard Henderson if (data[1] != -1) { 393661766fe9SRichard Henderson env->iaoq_b = data[1]; 393761766fe9SRichard Henderson } 393861766fe9SRichard Henderson /* Since we were executing the instruction at IAOQ_F, and took some 393961766fe9SRichard Henderson sort of action that provoked the cpu_restore_state, we can infer 394061766fe9SRichard Henderson that the instruction was not nullified. */ 394161766fe9SRichard Henderson env->psw_n = 0; 394261766fe9SRichard Henderson } 3943