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 2861766fe9SRichard Henderson #include "exec/helper-proto.h" 2961766fe9SRichard Henderson #include "exec/helper-gen.h" 3061766fe9SRichard Henderson 3161766fe9SRichard Henderson #include "trace-tcg.h" 3261766fe9SRichard Henderson #include "exec/log.h" 3361766fe9SRichard Henderson 3461766fe9SRichard Henderson typedef struct DisasCond { 3561766fe9SRichard Henderson TCGCond c; 3661766fe9SRichard Henderson TCGv a0, a1; 3761766fe9SRichard Henderson bool a0_is_n; 3861766fe9SRichard Henderson bool a1_is_0; 3961766fe9SRichard Henderson } DisasCond; 4061766fe9SRichard Henderson 4161766fe9SRichard Henderson typedef struct DisasContext { 4261766fe9SRichard Henderson struct TranslationBlock *tb; 4361766fe9SRichard Henderson CPUState *cs; 4461766fe9SRichard Henderson 4561766fe9SRichard Henderson target_ulong iaoq_f; 4661766fe9SRichard Henderson target_ulong iaoq_b; 4761766fe9SRichard Henderson target_ulong iaoq_n; 4861766fe9SRichard Henderson TCGv iaoq_n_var; 4961766fe9SRichard Henderson 5061766fe9SRichard Henderson int ntemps; 5161766fe9SRichard Henderson TCGv temps[8]; 5261766fe9SRichard Henderson 5361766fe9SRichard Henderson DisasCond null_cond; 5461766fe9SRichard Henderson TCGLabel *null_lab; 5561766fe9SRichard Henderson 5661766fe9SRichard Henderson bool singlestep_enabled; 5761766fe9SRichard Henderson bool psw_n_nonzero; 5861766fe9SRichard Henderson } DisasContext; 5961766fe9SRichard Henderson 6061766fe9SRichard Henderson /* Return values from translate_one, indicating the state of the TB. 6161766fe9SRichard Henderson Note that zero indicates that we are not exiting the TB. */ 6261766fe9SRichard Henderson 6361766fe9SRichard Henderson typedef enum { 6461766fe9SRichard Henderson NO_EXIT, 6561766fe9SRichard Henderson 6661766fe9SRichard Henderson /* We have emitted one or more goto_tb. No fixup required. */ 6761766fe9SRichard Henderson EXIT_GOTO_TB, 6861766fe9SRichard Henderson 6961766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 7061766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 7161766fe9SRichard Henderson EXIT_IAQ_N_UPDATED, 7261766fe9SRichard Henderson 7361766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 7461766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 7561766fe9SRichard Henderson EXIT_IAQ_N_STALE, 7661766fe9SRichard Henderson 7761766fe9SRichard Henderson /* We are ending the TB with a noreturn function call, e.g. longjmp. 7861766fe9SRichard Henderson No following code will be executed. */ 7961766fe9SRichard Henderson EXIT_NORETURN, 8061766fe9SRichard Henderson } ExitStatus; 8161766fe9SRichard Henderson 8261766fe9SRichard Henderson typedef struct DisasInsn { 8361766fe9SRichard Henderson uint32_t insn, mask; 8461766fe9SRichard Henderson ExitStatus (*trans)(DisasContext *ctx, uint32_t insn, 8561766fe9SRichard Henderson const struct DisasInsn *f); 86b2167459SRichard Henderson union { 87b2167459SRichard Henderson void (*f_ttt)(TCGv, TCGv, TCGv); 88b2167459SRichard Henderson }; 8961766fe9SRichard Henderson } DisasInsn; 9061766fe9SRichard Henderson 9161766fe9SRichard Henderson /* global register indexes */ 9261766fe9SRichard Henderson static TCGv_env cpu_env; 9361766fe9SRichard Henderson static TCGv cpu_gr[32]; 9461766fe9SRichard Henderson static TCGv cpu_iaoq_f; 9561766fe9SRichard Henderson static TCGv cpu_iaoq_b; 9661766fe9SRichard Henderson static TCGv cpu_sar; 9761766fe9SRichard Henderson static TCGv cpu_psw_n; 9861766fe9SRichard Henderson static TCGv cpu_psw_v; 9961766fe9SRichard Henderson static TCGv cpu_psw_cb; 10061766fe9SRichard Henderson static TCGv cpu_psw_cb_msb; 10161766fe9SRichard Henderson static TCGv cpu_cr26; 10261766fe9SRichard Henderson static TCGv cpu_cr27; 10361766fe9SRichard Henderson 10461766fe9SRichard Henderson #include "exec/gen-icount.h" 10561766fe9SRichard Henderson 10661766fe9SRichard Henderson void hppa_translate_init(void) 10761766fe9SRichard Henderson { 10861766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 10961766fe9SRichard Henderson 11061766fe9SRichard Henderson typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar; 11161766fe9SRichard Henderson static const GlobalVar vars[] = { 11261766fe9SRichard Henderson DEF_VAR(sar), 11361766fe9SRichard Henderson DEF_VAR(cr26), 11461766fe9SRichard Henderson DEF_VAR(cr27), 11561766fe9SRichard Henderson DEF_VAR(psw_n), 11661766fe9SRichard Henderson DEF_VAR(psw_v), 11761766fe9SRichard Henderson DEF_VAR(psw_cb), 11861766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 11961766fe9SRichard Henderson DEF_VAR(iaoq_f), 12061766fe9SRichard Henderson DEF_VAR(iaoq_b), 12161766fe9SRichard Henderson }; 12261766fe9SRichard Henderson 12361766fe9SRichard Henderson #undef DEF_VAR 12461766fe9SRichard Henderson 12561766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 12661766fe9SRichard Henderson static const char gr_names[32][4] = { 12761766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 12861766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 12961766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 13061766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 13161766fe9SRichard Henderson }; 13261766fe9SRichard Henderson 13361766fe9SRichard Henderson static bool done_init = 0; 13461766fe9SRichard Henderson int i; 13561766fe9SRichard Henderson 13661766fe9SRichard Henderson if (done_init) { 13761766fe9SRichard Henderson return; 13861766fe9SRichard Henderson } 13961766fe9SRichard Henderson done_init = 1; 14061766fe9SRichard Henderson 14161766fe9SRichard Henderson cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); 14261766fe9SRichard Henderson tcg_ctx.tcg_env = cpu_env; 14361766fe9SRichard Henderson 14461766fe9SRichard Henderson TCGV_UNUSED(cpu_gr[0]); 14561766fe9SRichard Henderson for (i = 1; i < 32; i++) { 14661766fe9SRichard Henderson cpu_gr[i] = tcg_global_mem_new(cpu_env, 14761766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 14861766fe9SRichard Henderson gr_names[i]); 14961766fe9SRichard Henderson } 15061766fe9SRichard Henderson 15161766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 15261766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 15361766fe9SRichard Henderson *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name); 15461766fe9SRichard Henderson } 15561766fe9SRichard Henderson } 15661766fe9SRichard Henderson 157129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 158129e9cc3SRichard Henderson { 159129e9cc3SRichard Henderson DisasCond r = { .c = TCG_COND_NEVER }; 160129e9cc3SRichard Henderson TCGV_UNUSED(r.a0); 161129e9cc3SRichard Henderson TCGV_UNUSED(r.a1); 162129e9cc3SRichard Henderson return r; 163129e9cc3SRichard Henderson } 164129e9cc3SRichard Henderson 165129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 166129e9cc3SRichard Henderson { 167129e9cc3SRichard Henderson DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true }; 168129e9cc3SRichard Henderson r.a0 = cpu_psw_n; 169129e9cc3SRichard Henderson TCGV_UNUSED(r.a1); 170129e9cc3SRichard Henderson return r; 171129e9cc3SRichard Henderson } 172129e9cc3SRichard Henderson 173129e9cc3SRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv a0) 174129e9cc3SRichard Henderson { 175129e9cc3SRichard Henderson DisasCond r = { .c = c, .a1_is_0 = true }; 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 TCGV_UNUSED(r.a1); 181129e9cc3SRichard Henderson 182129e9cc3SRichard Henderson return r; 183129e9cc3SRichard Henderson } 184129e9cc3SRichard Henderson 185129e9cc3SRichard Henderson static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1) 186129e9cc3SRichard Henderson { 187129e9cc3SRichard Henderson DisasCond r = { .c = c }; 188129e9cc3SRichard Henderson 189129e9cc3SRichard Henderson assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 190129e9cc3SRichard Henderson r.a0 = tcg_temp_new(); 191129e9cc3SRichard Henderson tcg_gen_mov_tl(r.a0, a0); 192129e9cc3SRichard Henderson r.a1 = tcg_temp_new(); 193129e9cc3SRichard Henderson tcg_gen_mov_tl(r.a1, a1); 194129e9cc3SRichard Henderson 195129e9cc3SRichard Henderson return r; 196129e9cc3SRichard Henderson } 197129e9cc3SRichard Henderson 198129e9cc3SRichard Henderson static void cond_prep(DisasCond *cond) 199129e9cc3SRichard Henderson { 200129e9cc3SRichard Henderson if (cond->a1_is_0) { 201129e9cc3SRichard Henderson cond->a1_is_0 = false; 202129e9cc3SRichard Henderson cond->a1 = tcg_const_tl(0); 203129e9cc3SRichard Henderson } 204129e9cc3SRichard Henderson } 205129e9cc3SRichard Henderson 206129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 207129e9cc3SRichard Henderson { 208129e9cc3SRichard Henderson switch (cond->c) { 209129e9cc3SRichard Henderson default: 210129e9cc3SRichard Henderson if (!cond->a0_is_n) { 211129e9cc3SRichard Henderson tcg_temp_free(cond->a0); 212129e9cc3SRichard Henderson } 213129e9cc3SRichard Henderson if (!cond->a1_is_0) { 214129e9cc3SRichard Henderson tcg_temp_free(cond->a1); 215129e9cc3SRichard Henderson } 216129e9cc3SRichard Henderson cond->a0_is_n = false; 217129e9cc3SRichard Henderson cond->a1_is_0 = false; 218129e9cc3SRichard Henderson TCGV_UNUSED(cond->a0); 219129e9cc3SRichard Henderson TCGV_UNUSED(cond->a1); 220129e9cc3SRichard Henderson /* fallthru */ 221129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 222129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 223129e9cc3SRichard Henderson break; 224129e9cc3SRichard Henderson case TCG_COND_NEVER: 225129e9cc3SRichard Henderson break; 226129e9cc3SRichard Henderson } 227129e9cc3SRichard Henderson } 228129e9cc3SRichard Henderson 22961766fe9SRichard Henderson static TCGv get_temp(DisasContext *ctx) 23061766fe9SRichard Henderson { 23161766fe9SRichard Henderson unsigned i = ctx->ntemps++; 23261766fe9SRichard Henderson g_assert(i < ARRAY_SIZE(ctx->temps)); 23361766fe9SRichard Henderson return ctx->temps[i] = tcg_temp_new(); 23461766fe9SRichard Henderson } 23561766fe9SRichard Henderson 23661766fe9SRichard Henderson static TCGv load_const(DisasContext *ctx, target_long v) 23761766fe9SRichard Henderson { 23861766fe9SRichard Henderson TCGv t = get_temp(ctx); 23961766fe9SRichard Henderson tcg_gen_movi_tl(t, v); 24061766fe9SRichard Henderson return t; 24161766fe9SRichard Henderson } 24261766fe9SRichard Henderson 24361766fe9SRichard Henderson static TCGv load_gpr(DisasContext *ctx, unsigned reg) 24461766fe9SRichard Henderson { 24561766fe9SRichard Henderson if (reg == 0) { 24661766fe9SRichard Henderson TCGv t = get_temp(ctx); 24761766fe9SRichard Henderson tcg_gen_movi_tl(t, 0); 24861766fe9SRichard Henderson return t; 24961766fe9SRichard Henderson } else { 25061766fe9SRichard Henderson return cpu_gr[reg]; 25161766fe9SRichard Henderson } 25261766fe9SRichard Henderson } 25361766fe9SRichard Henderson 25461766fe9SRichard Henderson static TCGv dest_gpr(DisasContext *ctx, unsigned reg) 25561766fe9SRichard Henderson { 256129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 25761766fe9SRichard Henderson return get_temp(ctx); 25861766fe9SRichard Henderson } else { 25961766fe9SRichard Henderson return cpu_gr[reg]; 26061766fe9SRichard Henderson } 26161766fe9SRichard Henderson } 26261766fe9SRichard Henderson 263129e9cc3SRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t) 264129e9cc3SRichard Henderson { 265129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 266129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 267129e9cc3SRichard Henderson tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0, 268129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 269129e9cc3SRichard Henderson } else { 270129e9cc3SRichard Henderson tcg_gen_mov_tl(dest, t); 271129e9cc3SRichard Henderson } 272129e9cc3SRichard Henderson } 273129e9cc3SRichard Henderson 274129e9cc3SRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t) 275129e9cc3SRichard Henderson { 276129e9cc3SRichard Henderson if (reg != 0) { 277129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 278129e9cc3SRichard Henderson } 279129e9cc3SRichard Henderson } 280129e9cc3SRichard Henderson 281*96d6407fSRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 282*96d6407fSRichard Henderson # define HI_OFS 0 283*96d6407fSRichard Henderson # define LO_OFS 4 284*96d6407fSRichard Henderson #else 285*96d6407fSRichard Henderson # define HI_OFS 4 286*96d6407fSRichard Henderson # define LO_OFS 0 287*96d6407fSRichard Henderson #endif 288*96d6407fSRichard Henderson 289*96d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 290*96d6407fSRichard Henderson { 291*96d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 292*96d6407fSRichard Henderson tcg_gen_ld_i32(ret, cpu_env, 293*96d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 294*96d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 295*96d6407fSRichard Henderson return ret; 296*96d6407fSRichard Henderson } 297*96d6407fSRichard Henderson 298*96d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 299*96d6407fSRichard Henderson { 300*96d6407fSRichard Henderson tcg_gen_st_i32(val, cpu_env, 301*96d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 302*96d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 303*96d6407fSRichard Henderson } 304*96d6407fSRichard Henderson 305*96d6407fSRichard Henderson #undef HI_OFS 306*96d6407fSRichard Henderson #undef LO_OFS 307*96d6407fSRichard Henderson 308*96d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 309*96d6407fSRichard Henderson { 310*96d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 311*96d6407fSRichard Henderson tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt])); 312*96d6407fSRichard Henderson return ret; 313*96d6407fSRichard Henderson } 314*96d6407fSRichard Henderson 315*96d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 316*96d6407fSRichard Henderson { 317*96d6407fSRichard Henderson tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt])); 318*96d6407fSRichard Henderson } 319*96d6407fSRichard Henderson 320129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 321129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 322129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 323129e9cc3SRichard Henderson { 324129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 325129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 326129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 327129e9cc3SRichard Henderson 328129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 329129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 330129e9cc3SRichard Henderson 331129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 332129e9cc3SRichard Henderson if (ctx->null_cond.a0_is_n) { 333129e9cc3SRichard Henderson ctx->null_cond.a0_is_n = false; 334129e9cc3SRichard Henderson ctx->null_cond.a0 = tcg_temp_new(); 335129e9cc3SRichard Henderson tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n); 336129e9cc3SRichard Henderson } 337129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 338129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 339129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 340129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 341129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 342129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, 0); 343129e9cc3SRichard Henderson } 344129e9cc3SRichard Henderson 345129e9cc3SRichard Henderson tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0, 346129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 347129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 348129e9cc3SRichard Henderson } 349129e9cc3SRichard Henderson } 350129e9cc3SRichard Henderson 351129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 352129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 353129e9cc3SRichard Henderson { 354129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 355129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 356129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, 0); 357129e9cc3SRichard Henderson } 358129e9cc3SRichard Henderson return; 359129e9cc3SRichard Henderson } 360129e9cc3SRichard Henderson if (!ctx->null_cond.a0_is_n) { 361129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 362129e9cc3SRichard Henderson tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n, 363129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 364129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 365129e9cc3SRichard Henderson } 366129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 367129e9cc3SRichard Henderson } 368129e9cc3SRichard Henderson 369129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 370129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 371129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 372129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 373129e9cc3SRichard Henderson { 374129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 375129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, x); 376129e9cc3SRichard Henderson } 377129e9cc3SRichard Henderson } 378129e9cc3SRichard Henderson 379129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 380129e9cc3SRichard Henderson This is the pair to nullify_over. */ 381129e9cc3SRichard Henderson static ExitStatus nullify_end(DisasContext *ctx, ExitStatus status) 382129e9cc3SRichard Henderson { 383129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 384129e9cc3SRichard Henderson 385129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 386129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 387129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 388129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 389129e9cc3SRichard Henderson return status; 390129e9cc3SRichard Henderson } 391129e9cc3SRichard Henderson ctx->null_lab = NULL; 392129e9cc3SRichard Henderson 393129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 394129e9cc3SRichard Henderson /* The next instruction will be unconditional, 395129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 396129e9cc3SRichard Henderson gen_set_label(null_lab); 397129e9cc3SRichard Henderson } else { 398129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 399129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 400129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 401129e9cc3SRichard Henderson label we have the proper value in place. */ 402129e9cc3SRichard Henderson nullify_save(ctx); 403129e9cc3SRichard Henderson gen_set_label(null_lab); 404129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 405129e9cc3SRichard Henderson } 406129e9cc3SRichard Henderson 407129e9cc3SRichard Henderson assert(status != EXIT_GOTO_TB && status != EXIT_IAQ_N_UPDATED); 408129e9cc3SRichard Henderson if (status == EXIT_NORETURN) { 409129e9cc3SRichard Henderson status = NO_EXIT; 410129e9cc3SRichard Henderson } 411129e9cc3SRichard Henderson return status; 412129e9cc3SRichard Henderson } 413129e9cc3SRichard Henderson 41461766fe9SRichard Henderson static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval) 41561766fe9SRichard Henderson { 41661766fe9SRichard Henderson if (unlikely(ival == -1)) { 41761766fe9SRichard Henderson tcg_gen_mov_tl(dest, vval); 41861766fe9SRichard Henderson } else { 41961766fe9SRichard Henderson tcg_gen_movi_tl(dest, ival); 42061766fe9SRichard Henderson } 42161766fe9SRichard Henderson } 42261766fe9SRichard Henderson 42361766fe9SRichard Henderson static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp) 42461766fe9SRichard Henderson { 42561766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 42661766fe9SRichard Henderson } 42761766fe9SRichard Henderson 42861766fe9SRichard Henderson static void gen_excp_1(int exception) 42961766fe9SRichard Henderson { 43061766fe9SRichard Henderson TCGv_i32 t = tcg_const_i32(exception); 43161766fe9SRichard Henderson gen_helper_excp(cpu_env, t); 43261766fe9SRichard Henderson tcg_temp_free_i32(t); 43361766fe9SRichard Henderson } 43461766fe9SRichard Henderson 43561766fe9SRichard Henderson static ExitStatus gen_excp(DisasContext *ctx, int exception) 43661766fe9SRichard Henderson { 43761766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 43861766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 439129e9cc3SRichard Henderson nullify_save(ctx); 44061766fe9SRichard Henderson gen_excp_1(exception); 44161766fe9SRichard Henderson return EXIT_NORETURN; 44261766fe9SRichard Henderson } 44361766fe9SRichard Henderson 44461766fe9SRichard Henderson static ExitStatus gen_illegal(DisasContext *ctx) 44561766fe9SRichard Henderson { 446129e9cc3SRichard Henderson nullify_over(ctx); 447129e9cc3SRichard Henderson return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL)); 44861766fe9SRichard Henderson } 44961766fe9SRichard Henderson 45061766fe9SRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ulong dest) 45161766fe9SRichard Henderson { 45261766fe9SRichard Henderson /* Suppress goto_tb in the case of single-steping and IO. */ 45361766fe9SRichard Henderson if ((ctx->tb->cflags & CF_LAST_IO) || ctx->singlestep_enabled) { 45461766fe9SRichard Henderson return false; 45561766fe9SRichard Henderson } 45661766fe9SRichard Henderson return true; 45761766fe9SRichard Henderson } 45861766fe9SRichard Henderson 459129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 460129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 461129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 462129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 463129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 464129e9cc3SRichard Henderson { 465129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 466129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 467129e9cc3SRichard Henderson } 468129e9cc3SRichard Henderson 46961766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 47061766fe9SRichard Henderson target_ulong f, target_ulong b) 47161766fe9SRichard Henderson { 47261766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 47361766fe9SRichard Henderson tcg_gen_goto_tb(which); 47461766fe9SRichard Henderson tcg_gen_movi_tl(cpu_iaoq_f, f); 47561766fe9SRichard Henderson tcg_gen_movi_tl(cpu_iaoq_b, b); 47661766fe9SRichard Henderson tcg_gen_exit_tb((uintptr_t)ctx->tb + which); 47761766fe9SRichard Henderson } else { 47861766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b); 47961766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var); 48061766fe9SRichard Henderson if (ctx->singlestep_enabled) { 48161766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 48261766fe9SRichard Henderson } else { 48361766fe9SRichard Henderson tcg_gen_exit_tb(0); 48461766fe9SRichard Henderson } 48561766fe9SRichard Henderson } 48661766fe9SRichard Henderson } 48761766fe9SRichard Henderson 488b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign, 489b2167459SRichard Henderson with the rest of the field becoming the least significant bits. */ 490b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len) 491b2167459SRichard Henderson { 492b2167459SRichard Henderson target_ulong x = -(target_ulong)extract32(val, pos, 1); 493b2167459SRichard Henderson x = (x << (len - 1)) | extract32(val, pos + 1, len - 1); 494b2167459SRichard Henderson return x; 495b2167459SRichard Henderson } 496b2167459SRichard Henderson 49798cd9ca7SRichard Henderson static target_long assemble_12(uint32_t insn) 49898cd9ca7SRichard Henderson { 49998cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 50098cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 50198cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 50298cd9ca7SRichard Henderson return x; 50398cd9ca7SRichard Henderson } 50498cd9ca7SRichard Henderson 505b2167459SRichard Henderson static target_long assemble_16(uint32_t insn) 506b2167459SRichard Henderson { 507b2167459SRichard Henderson /* Take the name from PA2.0, which produces a 16-bit number 508b2167459SRichard Henderson only with wide mode; otherwise a 14-bit number. Since we don't 509b2167459SRichard Henderson implement wide mode, this is always the 14-bit number. */ 510b2167459SRichard Henderson return low_sextract(insn, 0, 14); 511b2167459SRichard Henderson } 512b2167459SRichard Henderson 513*96d6407fSRichard Henderson static target_long assemble_16a(uint32_t insn) 514*96d6407fSRichard Henderson { 515*96d6407fSRichard Henderson /* Take the name from PA2.0, which produces a 14-bit shifted number 516*96d6407fSRichard Henderson only with wide mode; otherwise a 12-bit shifted number. Since we 517*96d6407fSRichard Henderson don't implement wide mode, this is always the 12-bit number. */ 518*96d6407fSRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 519*96d6407fSRichard Henderson x = (x << 11) | extract32(insn, 2, 11); 520*96d6407fSRichard Henderson return x << 2; 521*96d6407fSRichard Henderson } 522*96d6407fSRichard Henderson 52398cd9ca7SRichard Henderson static target_long assemble_17(uint32_t insn) 52498cd9ca7SRichard Henderson { 52598cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 52698cd9ca7SRichard Henderson x = (x << 5) | extract32(insn, 16, 5); 52798cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 52898cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 52998cd9ca7SRichard Henderson return x << 2; 53098cd9ca7SRichard Henderson } 53198cd9ca7SRichard Henderson 532b2167459SRichard Henderson static target_long assemble_21(uint32_t insn) 533b2167459SRichard Henderson { 534b2167459SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 535b2167459SRichard Henderson x = (x << 11) | extract32(insn, 1, 11); 536b2167459SRichard Henderson x = (x << 2) | extract32(insn, 14, 2); 537b2167459SRichard Henderson x = (x << 5) | extract32(insn, 16, 5); 538b2167459SRichard Henderson x = (x << 2) | extract32(insn, 12, 2); 539b2167459SRichard Henderson return x << 11; 540b2167459SRichard Henderson } 541b2167459SRichard Henderson 54298cd9ca7SRichard Henderson static target_long assemble_22(uint32_t insn) 54398cd9ca7SRichard Henderson { 54498cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 54598cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 16, 10); 54698cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 54798cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 54898cd9ca7SRichard Henderson return x << 2; 54998cd9ca7SRichard Henderson } 55098cd9ca7SRichard Henderson 551b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of 552b2167459SRichard Henderson the conditions, without describing their exact implementation. The 553b2167459SRichard Henderson interpretations do not stand up well when considering ADD,C and SUB,B. 554b2167459SRichard Henderson However, considering the Addition, Subtraction and Logical conditions 555b2167459SRichard Henderson as a whole it would appear that these relations are similar to what 556b2167459SRichard Henderson a traditional NZCV set of flags would produce. */ 557b2167459SRichard Henderson 558b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv) 559b2167459SRichard Henderson { 560b2167459SRichard Henderson DisasCond cond; 561b2167459SRichard Henderson TCGv tmp; 562b2167459SRichard Henderson 563b2167459SRichard Henderson switch (cf >> 1) { 564b2167459SRichard Henderson case 0: /* Never / TR */ 565b2167459SRichard Henderson cond = cond_make_f(); 566b2167459SRichard Henderson break; 567b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 568b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 569b2167459SRichard Henderson break; 570b2167459SRichard Henderson case 2: /* < / >= (N / !N) */ 571b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, res); 572b2167459SRichard Henderson break; 573b2167459SRichard Henderson case 3: /* <= / > (N | Z / !N & !Z) */ 574b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LE, res); 575b2167459SRichard Henderson break; 576b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 577b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 578b2167459SRichard Henderson break; 579b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 580b2167459SRichard Henderson tmp = tcg_temp_new(); 581b2167459SRichard Henderson tcg_gen_neg_tl(tmp, cb_msb); 582b2167459SRichard Henderson tcg_gen_and_tl(tmp, tmp, res); 583b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, tmp); 584b2167459SRichard Henderson tcg_temp_free(tmp); 585b2167459SRichard Henderson break; 586b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 587b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 588b2167459SRichard Henderson break; 589b2167459SRichard Henderson case 7: /* OD / EV */ 590b2167459SRichard Henderson tmp = tcg_temp_new(); 591b2167459SRichard Henderson tcg_gen_andi_tl(tmp, res, 1); 592b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 593b2167459SRichard Henderson tcg_temp_free(tmp); 594b2167459SRichard Henderson break; 595b2167459SRichard Henderson default: 596b2167459SRichard Henderson g_assert_not_reached(); 597b2167459SRichard Henderson } 598b2167459SRichard Henderson if (cf & 1) { 599b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 600b2167459SRichard Henderson } 601b2167459SRichard Henderson 602b2167459SRichard Henderson return cond; 603b2167459SRichard Henderson } 604b2167459SRichard Henderson 605b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 606b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 607b2167459SRichard Henderson deleted as unused. */ 608b2167459SRichard Henderson 609b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv) 610b2167459SRichard Henderson { 611b2167459SRichard Henderson DisasCond cond; 612b2167459SRichard Henderson 613b2167459SRichard Henderson switch (cf >> 1) { 614b2167459SRichard Henderson case 1: /* = / <> */ 615b2167459SRichard Henderson cond = cond_make(TCG_COND_EQ, in1, in2); 616b2167459SRichard Henderson break; 617b2167459SRichard Henderson case 2: /* < / >= */ 618b2167459SRichard Henderson cond = cond_make(TCG_COND_LT, in1, in2); 619b2167459SRichard Henderson break; 620b2167459SRichard Henderson case 3: /* <= / > */ 621b2167459SRichard Henderson cond = cond_make(TCG_COND_LE, in1, in2); 622b2167459SRichard Henderson break; 623b2167459SRichard Henderson case 4: /* << / >>= */ 624b2167459SRichard Henderson cond = cond_make(TCG_COND_LTU, in1, in2); 625b2167459SRichard Henderson break; 626b2167459SRichard Henderson case 5: /* <<= / >> */ 627b2167459SRichard Henderson cond = cond_make(TCG_COND_LEU, in1, in2); 628b2167459SRichard Henderson break; 629b2167459SRichard Henderson default: 630b2167459SRichard Henderson return do_cond(cf, res, sv, sv); 631b2167459SRichard Henderson } 632b2167459SRichard Henderson if (cf & 1) { 633b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 634b2167459SRichard Henderson } 635b2167459SRichard Henderson 636b2167459SRichard Henderson return cond; 637b2167459SRichard Henderson } 638b2167459SRichard Henderson 639b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not 640b2167459SRichard Henderson computed, and use of them is undefined. */ 641b2167459SRichard Henderson 642b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res) 643b2167459SRichard Henderson { 644b2167459SRichard Henderson switch (cf >> 1) { 645b2167459SRichard Henderson case 4: case 5: case 6: 646b2167459SRichard Henderson cf &= 1; 647b2167459SRichard Henderson break; 648b2167459SRichard Henderson } 649b2167459SRichard Henderson return do_cond(cf, res, res, res); 650b2167459SRichard Henderson } 651b2167459SRichard Henderson 65298cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 65398cd9ca7SRichard Henderson 65498cd9ca7SRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv res) 65598cd9ca7SRichard Henderson { 65698cd9ca7SRichard Henderson unsigned c, f; 65798cd9ca7SRichard Henderson 65898cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 65998cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 66098cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 66198cd9ca7SRichard Henderson c = orig & 3; 66298cd9ca7SRichard Henderson if (c == 3) { 66398cd9ca7SRichard Henderson c = 7; 66498cd9ca7SRichard Henderson } 66598cd9ca7SRichard Henderson f = (orig & 4) / 4; 66698cd9ca7SRichard Henderson 66798cd9ca7SRichard Henderson return do_log_cond(c * 2 + f, res); 66898cd9ca7SRichard Henderson } 66998cd9ca7SRichard Henderson 670b2167459SRichard Henderson /* Similar, but for unit conditions. */ 671b2167459SRichard Henderson 672b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2) 673b2167459SRichard Henderson { 674b2167459SRichard Henderson DisasCond cond; 675b2167459SRichard Henderson TCGv tmp, cb; 676b2167459SRichard Henderson 677b2167459SRichard Henderson TCGV_UNUSED(cb); 678b2167459SRichard Henderson if (cf & 8) { 679b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 680b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 681b2167459SRichard Henderson * leaves us with carry bits spread across two words. 682b2167459SRichard Henderson */ 683b2167459SRichard Henderson cb = tcg_temp_new(); 684b2167459SRichard Henderson tmp = tcg_temp_new(); 685b2167459SRichard Henderson tcg_gen_or_tl(cb, in1, in2); 686b2167459SRichard Henderson tcg_gen_and_tl(tmp, in1, in2); 687b2167459SRichard Henderson tcg_gen_andc_tl(cb, cb, res); 688b2167459SRichard Henderson tcg_gen_or_tl(cb, cb, tmp); 689b2167459SRichard Henderson tcg_temp_free(tmp); 690b2167459SRichard Henderson } 691b2167459SRichard Henderson 692b2167459SRichard Henderson switch (cf >> 1) { 693b2167459SRichard Henderson case 0: /* never / TR */ 694b2167459SRichard Henderson case 1: /* undefined */ 695b2167459SRichard Henderson case 5: /* undefined */ 696b2167459SRichard Henderson cond = cond_make_f(); 697b2167459SRichard Henderson break; 698b2167459SRichard Henderson 699b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 700b2167459SRichard Henderson /* See hasless(v,1) from 701b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 702b2167459SRichard Henderson */ 703b2167459SRichard Henderson tmp = tcg_temp_new(); 704b2167459SRichard Henderson tcg_gen_subi_tl(tmp, res, 0x01010101u); 705b2167459SRichard Henderson tcg_gen_andc_tl(tmp, tmp, res); 706b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x80808080u); 707b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 708b2167459SRichard Henderson tcg_temp_free(tmp); 709b2167459SRichard Henderson break; 710b2167459SRichard Henderson 711b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 712b2167459SRichard Henderson tmp = tcg_temp_new(); 713b2167459SRichard Henderson tcg_gen_subi_tl(tmp, res, 0x00010001u); 714b2167459SRichard Henderson tcg_gen_andc_tl(tmp, tmp, res); 715b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x80008000u); 716b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 717b2167459SRichard Henderson tcg_temp_free(tmp); 718b2167459SRichard Henderson break; 719b2167459SRichard Henderson 720b2167459SRichard Henderson case 4: /* SDC / NDC */ 721b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x88888888u); 722b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 723b2167459SRichard Henderson break; 724b2167459SRichard Henderson 725b2167459SRichard Henderson case 6: /* SBC / NBC */ 726b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x80808080u); 727b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 728b2167459SRichard Henderson break; 729b2167459SRichard Henderson 730b2167459SRichard Henderson case 7: /* SHC / NHC */ 731b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x80008000u); 732b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 733b2167459SRichard Henderson break; 734b2167459SRichard Henderson 735b2167459SRichard Henderson default: 736b2167459SRichard Henderson g_assert_not_reached(); 737b2167459SRichard Henderson } 738b2167459SRichard Henderson if (cf & 8) { 739b2167459SRichard Henderson tcg_temp_free(cb); 740b2167459SRichard Henderson } 741b2167459SRichard Henderson if (cf & 1) { 742b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 743b2167459SRichard Henderson } 744b2167459SRichard Henderson 745b2167459SRichard Henderson return cond; 746b2167459SRichard Henderson } 747b2167459SRichard Henderson 748b2167459SRichard Henderson /* Compute signed overflow for addition. */ 749b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2) 750b2167459SRichard Henderson { 751b2167459SRichard Henderson TCGv sv = get_temp(ctx); 752b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 753b2167459SRichard Henderson 754b2167459SRichard Henderson tcg_gen_xor_tl(sv, res, in1); 755b2167459SRichard Henderson tcg_gen_xor_tl(tmp, in1, in2); 756b2167459SRichard Henderson tcg_gen_andc_tl(sv, sv, tmp); 757b2167459SRichard Henderson tcg_temp_free(tmp); 758b2167459SRichard Henderson 759b2167459SRichard Henderson return sv; 760b2167459SRichard Henderson } 761b2167459SRichard Henderson 762b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 763b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2) 764b2167459SRichard Henderson { 765b2167459SRichard Henderson TCGv sv = get_temp(ctx); 766b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 767b2167459SRichard Henderson 768b2167459SRichard Henderson tcg_gen_xor_tl(sv, res, in1); 769b2167459SRichard Henderson tcg_gen_xor_tl(tmp, in1, in2); 770b2167459SRichard Henderson tcg_gen_and_tl(sv, sv, tmp); 771b2167459SRichard Henderson tcg_temp_free(tmp); 772b2167459SRichard Henderson 773b2167459SRichard Henderson return sv; 774b2167459SRichard Henderson } 775b2167459SRichard Henderson 776b2167459SRichard Henderson static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 777b2167459SRichard Henderson unsigned shift, bool is_l, bool is_tsv, bool is_tc, 778b2167459SRichard Henderson bool is_c, unsigned cf) 779b2167459SRichard Henderson { 780b2167459SRichard Henderson TCGv dest, cb, cb_msb, sv, tmp; 781b2167459SRichard Henderson unsigned c = cf >> 1; 782b2167459SRichard Henderson DisasCond cond; 783b2167459SRichard Henderson 784b2167459SRichard Henderson dest = tcg_temp_new(); 785b2167459SRichard Henderson TCGV_UNUSED(cb); 786b2167459SRichard Henderson TCGV_UNUSED(cb_msb); 787b2167459SRichard Henderson 788b2167459SRichard Henderson if (shift) { 789b2167459SRichard Henderson tmp = get_temp(ctx); 790b2167459SRichard Henderson tcg_gen_shli_tl(tmp, in1, shift); 791b2167459SRichard Henderson in1 = tmp; 792b2167459SRichard Henderson } 793b2167459SRichard Henderson 794b2167459SRichard Henderson if (!is_l || c == 4 || c == 5) { 795b2167459SRichard Henderson TCGv zero = tcg_const_tl(0); 796b2167459SRichard Henderson cb_msb = get_temp(ctx); 797b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero); 798b2167459SRichard Henderson if (is_c) { 799b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero); 800b2167459SRichard Henderson } 801b2167459SRichard Henderson tcg_temp_free(zero); 802b2167459SRichard Henderson if (!is_l) { 803b2167459SRichard Henderson cb = get_temp(ctx); 804b2167459SRichard Henderson tcg_gen_xor_tl(cb, in1, in2); 805b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 806b2167459SRichard Henderson } 807b2167459SRichard Henderson } else { 808b2167459SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 809b2167459SRichard Henderson if (is_c) { 810b2167459SRichard Henderson tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb); 811b2167459SRichard Henderson } 812b2167459SRichard Henderson } 813b2167459SRichard Henderson 814b2167459SRichard Henderson /* Compute signed overflow if required. */ 815b2167459SRichard Henderson TCGV_UNUSED(sv); 816b2167459SRichard Henderson if (is_tsv || c == 6) { 817b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 818b2167459SRichard Henderson if (is_tsv) { 819b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 820b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 821b2167459SRichard Henderson } 822b2167459SRichard Henderson } 823b2167459SRichard Henderson 824b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 825b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 826b2167459SRichard Henderson if (is_tc) { 827b2167459SRichard Henderson cond_prep(&cond); 828b2167459SRichard Henderson tmp = tcg_temp_new(); 829b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 830b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 831b2167459SRichard Henderson tcg_temp_free(tmp); 832b2167459SRichard Henderson } 833b2167459SRichard Henderson 834b2167459SRichard Henderson /* Write back the result. */ 835b2167459SRichard Henderson if (!is_l) { 836b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 837b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 838b2167459SRichard Henderson } 839b2167459SRichard Henderson save_gpr(ctx, rt, dest); 840b2167459SRichard Henderson tcg_temp_free(dest); 841b2167459SRichard Henderson 842b2167459SRichard Henderson /* Install the new nullification. */ 843b2167459SRichard Henderson cond_free(&ctx->null_cond); 844b2167459SRichard Henderson ctx->null_cond = cond; 845b2167459SRichard Henderson return NO_EXIT; 846b2167459SRichard Henderson } 847b2167459SRichard Henderson 848b2167459SRichard Henderson static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 849b2167459SRichard Henderson bool is_tsv, bool is_b, bool is_tc, unsigned cf) 850b2167459SRichard Henderson { 851b2167459SRichard Henderson TCGv dest, sv, cb, cb_msb, zero, tmp; 852b2167459SRichard Henderson unsigned c = cf >> 1; 853b2167459SRichard Henderson DisasCond cond; 854b2167459SRichard Henderson 855b2167459SRichard Henderson dest = tcg_temp_new(); 856b2167459SRichard Henderson cb = tcg_temp_new(); 857b2167459SRichard Henderson cb_msb = tcg_temp_new(); 858b2167459SRichard Henderson 859b2167459SRichard Henderson zero = tcg_const_tl(0); 860b2167459SRichard Henderson if (is_b) { 861b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 862b2167459SRichard Henderson tcg_gen_not_tl(cb, in2); 863b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero); 864b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero); 865b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, in1); 866b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 867b2167459SRichard Henderson } else { 868b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 869b2167459SRichard Henderson operations by seeding the high word with 1 and subtracting. */ 870b2167459SRichard Henderson tcg_gen_movi_tl(cb_msb, 1); 871b2167459SRichard Henderson tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero); 872b2167459SRichard Henderson tcg_gen_eqv_tl(cb, in1, in2); 873b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 874b2167459SRichard Henderson } 875b2167459SRichard Henderson tcg_temp_free(zero); 876b2167459SRichard Henderson 877b2167459SRichard Henderson /* Compute signed overflow if required. */ 878b2167459SRichard Henderson TCGV_UNUSED(sv); 879b2167459SRichard Henderson if (is_tsv || c == 6) { 880b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 881b2167459SRichard Henderson if (is_tsv) { 882b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 883b2167459SRichard Henderson } 884b2167459SRichard Henderson } 885b2167459SRichard Henderson 886b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 887b2167459SRichard Henderson if (!is_b) { 888b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 889b2167459SRichard Henderson } else { 890b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 891b2167459SRichard Henderson } 892b2167459SRichard Henderson 893b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 894b2167459SRichard Henderson if (is_tc) { 895b2167459SRichard Henderson cond_prep(&cond); 896b2167459SRichard Henderson tmp = tcg_temp_new(); 897b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 898b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 899b2167459SRichard Henderson tcg_temp_free(tmp); 900b2167459SRichard Henderson } 901b2167459SRichard Henderson 902b2167459SRichard Henderson /* Write back the result. */ 903b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 904b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 905b2167459SRichard Henderson save_gpr(ctx, rt, dest); 906b2167459SRichard Henderson tcg_temp_free(dest); 907b2167459SRichard Henderson 908b2167459SRichard Henderson /* Install the new nullification. */ 909b2167459SRichard Henderson cond_free(&ctx->null_cond); 910b2167459SRichard Henderson ctx->null_cond = cond; 911b2167459SRichard Henderson return NO_EXIT; 912b2167459SRichard Henderson } 913b2167459SRichard Henderson 914b2167459SRichard Henderson static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1, 915b2167459SRichard Henderson TCGv in2, unsigned cf) 916b2167459SRichard Henderson { 917b2167459SRichard Henderson TCGv dest, sv; 918b2167459SRichard Henderson DisasCond cond; 919b2167459SRichard Henderson 920b2167459SRichard Henderson dest = tcg_temp_new(); 921b2167459SRichard Henderson tcg_gen_sub_tl(dest, in1, in2); 922b2167459SRichard Henderson 923b2167459SRichard Henderson /* Compute signed overflow if required. */ 924b2167459SRichard Henderson TCGV_UNUSED(sv); 925b2167459SRichard Henderson if ((cf >> 1) == 6) { 926b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 927b2167459SRichard Henderson } 928b2167459SRichard Henderson 929b2167459SRichard Henderson /* Form the condition for the compare. */ 930b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 931b2167459SRichard Henderson 932b2167459SRichard Henderson /* Clear. */ 933b2167459SRichard Henderson tcg_gen_movi_tl(dest, 0); 934b2167459SRichard Henderson save_gpr(ctx, rt, dest); 935b2167459SRichard Henderson tcg_temp_free(dest); 936b2167459SRichard Henderson 937b2167459SRichard Henderson /* Install the new nullification. */ 938b2167459SRichard Henderson cond_free(&ctx->null_cond); 939b2167459SRichard Henderson ctx->null_cond = cond; 940b2167459SRichard Henderson return NO_EXIT; 941b2167459SRichard Henderson } 942b2167459SRichard Henderson 943b2167459SRichard Henderson static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 944b2167459SRichard Henderson unsigned cf, void (*fn)(TCGv, TCGv, TCGv)) 945b2167459SRichard Henderson { 946b2167459SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 947b2167459SRichard Henderson 948b2167459SRichard Henderson /* Perform the operation, and writeback. */ 949b2167459SRichard Henderson fn(dest, in1, in2); 950b2167459SRichard Henderson save_gpr(ctx, rt, dest); 951b2167459SRichard Henderson 952b2167459SRichard Henderson /* Install the new nullification. */ 953b2167459SRichard Henderson cond_free(&ctx->null_cond); 954b2167459SRichard Henderson if (cf) { 955b2167459SRichard Henderson ctx->null_cond = do_log_cond(cf, dest); 956b2167459SRichard Henderson } 957b2167459SRichard Henderson return NO_EXIT; 958b2167459SRichard Henderson } 959b2167459SRichard Henderson 960b2167459SRichard Henderson static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1, 961b2167459SRichard Henderson TCGv in2, unsigned cf, bool is_tc, 962b2167459SRichard Henderson void (*fn)(TCGv, TCGv, TCGv)) 963b2167459SRichard Henderson { 964b2167459SRichard Henderson TCGv dest; 965b2167459SRichard Henderson DisasCond cond; 966b2167459SRichard Henderson 967b2167459SRichard Henderson if (cf == 0) { 968b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 969b2167459SRichard Henderson fn(dest, in1, in2); 970b2167459SRichard Henderson save_gpr(ctx, rt, dest); 971b2167459SRichard Henderson cond_free(&ctx->null_cond); 972b2167459SRichard Henderson } else { 973b2167459SRichard Henderson dest = tcg_temp_new(); 974b2167459SRichard Henderson fn(dest, in1, in2); 975b2167459SRichard Henderson 976b2167459SRichard Henderson cond = do_unit_cond(cf, dest, in1, in2); 977b2167459SRichard Henderson 978b2167459SRichard Henderson if (is_tc) { 979b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 980b2167459SRichard Henderson cond_prep(&cond); 981b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 982b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 983b2167459SRichard Henderson tcg_temp_free(tmp); 984b2167459SRichard Henderson } 985b2167459SRichard Henderson save_gpr(ctx, rt, dest); 986b2167459SRichard Henderson 987b2167459SRichard Henderson cond_free(&ctx->null_cond); 988b2167459SRichard Henderson ctx->null_cond = cond; 989b2167459SRichard Henderson } 990b2167459SRichard Henderson return NO_EXIT; 991b2167459SRichard Henderson } 992b2167459SRichard Henderson 993*96d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 994*96d6407fSRichard Henderson * < 0 for pre-modify, 995*96d6407fSRichard Henderson * > 0 for post-modify, 996*96d6407fSRichard Henderson * = 0 for no base register update. 997*96d6407fSRichard Henderson */ 998*96d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 999*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1000*96d6407fSRichard Henderson int modify, TCGMemOp mop) 1001*96d6407fSRichard Henderson { 1002*96d6407fSRichard Henderson TCGv addr, base; 1003*96d6407fSRichard Henderson 1004*96d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 1005*96d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 1006*96d6407fSRichard Henderson 1007*96d6407fSRichard Henderson addr = tcg_temp_new(); 1008*96d6407fSRichard Henderson base = load_gpr(ctx, rb); 1009*96d6407fSRichard Henderson 1010*96d6407fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 1011*96d6407fSRichard Henderson if (rx) { 1012*96d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 1013*96d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 1014*96d6407fSRichard Henderson } else { 1015*96d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 1016*96d6407fSRichard Henderson } 1017*96d6407fSRichard Henderson 1018*96d6407fSRichard Henderson if (modify == 0) { 1019*96d6407fSRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop); 1020*96d6407fSRichard Henderson } else { 1021*96d6407fSRichard Henderson tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base), 1022*96d6407fSRichard Henderson MMU_USER_IDX, mop); 1023*96d6407fSRichard Henderson save_gpr(ctx, rb, addr); 1024*96d6407fSRichard Henderson } 1025*96d6407fSRichard Henderson tcg_temp_free(addr); 1026*96d6407fSRichard Henderson } 1027*96d6407fSRichard Henderson 1028*96d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1029*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1030*96d6407fSRichard Henderson int modify, TCGMemOp mop) 1031*96d6407fSRichard Henderson { 1032*96d6407fSRichard Henderson TCGv addr, base; 1033*96d6407fSRichard Henderson 1034*96d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 1035*96d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 1036*96d6407fSRichard Henderson 1037*96d6407fSRichard Henderson addr = tcg_temp_new(); 1038*96d6407fSRichard Henderson base = load_gpr(ctx, rb); 1039*96d6407fSRichard Henderson 1040*96d6407fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 1041*96d6407fSRichard Henderson if (rx) { 1042*96d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 1043*96d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 1044*96d6407fSRichard Henderson } else { 1045*96d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 1046*96d6407fSRichard Henderson } 1047*96d6407fSRichard Henderson 1048*96d6407fSRichard Henderson if (modify == 0) { 1049*96d6407fSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop); 1050*96d6407fSRichard Henderson } else { 1051*96d6407fSRichard Henderson tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base), 1052*96d6407fSRichard Henderson MMU_USER_IDX, mop); 1053*96d6407fSRichard Henderson save_gpr(ctx, rb, addr); 1054*96d6407fSRichard Henderson } 1055*96d6407fSRichard Henderson tcg_temp_free(addr); 1056*96d6407fSRichard Henderson } 1057*96d6407fSRichard Henderson 1058*96d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1059*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1060*96d6407fSRichard Henderson int modify, TCGMemOp mop) 1061*96d6407fSRichard Henderson { 1062*96d6407fSRichard Henderson TCGv addr, base; 1063*96d6407fSRichard Henderson 1064*96d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 1065*96d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 1066*96d6407fSRichard Henderson 1067*96d6407fSRichard Henderson addr = tcg_temp_new(); 1068*96d6407fSRichard Henderson base = load_gpr(ctx, rb); 1069*96d6407fSRichard Henderson 1070*96d6407fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 1071*96d6407fSRichard Henderson if (rx) { 1072*96d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 1073*96d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 1074*96d6407fSRichard Henderson } else { 1075*96d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 1076*96d6407fSRichard Henderson } 1077*96d6407fSRichard Henderson 1078*96d6407fSRichard Henderson tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop); 1079*96d6407fSRichard Henderson 1080*96d6407fSRichard Henderson if (modify != 0) { 1081*96d6407fSRichard Henderson save_gpr(ctx, rb, addr); 1082*96d6407fSRichard Henderson } 1083*96d6407fSRichard Henderson tcg_temp_free(addr); 1084*96d6407fSRichard Henderson } 1085*96d6407fSRichard Henderson 1086*96d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1087*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1088*96d6407fSRichard Henderson int modify, TCGMemOp mop) 1089*96d6407fSRichard Henderson { 1090*96d6407fSRichard Henderson TCGv addr, base; 1091*96d6407fSRichard Henderson 1092*96d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 1093*96d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 1094*96d6407fSRichard Henderson 1095*96d6407fSRichard Henderson addr = tcg_temp_new(); 1096*96d6407fSRichard Henderson base = load_gpr(ctx, rb); 1097*96d6407fSRichard Henderson 1098*96d6407fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 1099*96d6407fSRichard Henderson if (rx) { 1100*96d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 1101*96d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 1102*96d6407fSRichard Henderson } else { 1103*96d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 1104*96d6407fSRichard Henderson } 1105*96d6407fSRichard Henderson 1106*96d6407fSRichard Henderson tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop); 1107*96d6407fSRichard Henderson 1108*96d6407fSRichard Henderson if (modify != 0) { 1109*96d6407fSRichard Henderson save_gpr(ctx, rb, addr); 1110*96d6407fSRichard Henderson } 1111*96d6407fSRichard Henderson tcg_temp_free(addr); 1112*96d6407fSRichard Henderson } 1113*96d6407fSRichard Henderson 1114*96d6407fSRichard Henderson #if TARGET_LONG_BITS == 64 1115*96d6407fSRichard Henderson #define do_load_tl do_load_64 1116*96d6407fSRichard Henderson #define do_store_tl do_store_64 1117*96d6407fSRichard Henderson #else 1118*96d6407fSRichard Henderson #define do_load_tl do_load_32 1119*96d6407fSRichard Henderson #define do_store_tl do_store_32 1120*96d6407fSRichard Henderson #endif 1121*96d6407fSRichard Henderson 1122*96d6407fSRichard Henderson static ExitStatus do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1123*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1124*96d6407fSRichard Henderson int modify, TCGMemOp mop) 1125*96d6407fSRichard Henderson { 1126*96d6407fSRichard Henderson TCGv dest; 1127*96d6407fSRichard Henderson 1128*96d6407fSRichard Henderson nullify_over(ctx); 1129*96d6407fSRichard Henderson 1130*96d6407fSRichard Henderson if (modify == 0) { 1131*96d6407fSRichard Henderson /* No base register update. */ 1132*96d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 1133*96d6407fSRichard Henderson } else { 1134*96d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1135*96d6407fSRichard Henderson dest = get_temp(ctx); 1136*96d6407fSRichard Henderson } 1137*96d6407fSRichard Henderson do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop); 1138*96d6407fSRichard Henderson save_gpr(ctx, rt, dest); 1139*96d6407fSRichard Henderson 1140*96d6407fSRichard Henderson return nullify_end(ctx, NO_EXIT); 1141*96d6407fSRichard Henderson } 1142*96d6407fSRichard Henderson 1143*96d6407fSRichard Henderson static ExitStatus do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1144*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1145*96d6407fSRichard Henderson int modify) 1146*96d6407fSRichard Henderson { 1147*96d6407fSRichard Henderson TCGv_i32 tmp; 1148*96d6407fSRichard Henderson 1149*96d6407fSRichard Henderson nullify_over(ctx); 1150*96d6407fSRichard Henderson 1151*96d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 1152*96d6407fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL); 1153*96d6407fSRichard Henderson save_frw_i32(rt, tmp); 1154*96d6407fSRichard Henderson tcg_temp_free_i32(tmp); 1155*96d6407fSRichard Henderson 1156*96d6407fSRichard Henderson if (rt == 0) { 1157*96d6407fSRichard Henderson gen_helper_loaded_fr0(cpu_env); 1158*96d6407fSRichard Henderson } 1159*96d6407fSRichard Henderson 1160*96d6407fSRichard Henderson return nullify_end(ctx, NO_EXIT); 1161*96d6407fSRichard Henderson } 1162*96d6407fSRichard Henderson 1163*96d6407fSRichard Henderson static ExitStatus do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1164*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1165*96d6407fSRichard Henderson int modify) 1166*96d6407fSRichard Henderson { 1167*96d6407fSRichard Henderson TCGv_i64 tmp; 1168*96d6407fSRichard Henderson 1169*96d6407fSRichard Henderson nullify_over(ctx); 1170*96d6407fSRichard Henderson 1171*96d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1172*96d6407fSRichard Henderson do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ); 1173*96d6407fSRichard Henderson save_frd(rt, tmp); 1174*96d6407fSRichard Henderson tcg_temp_free_i64(tmp); 1175*96d6407fSRichard Henderson 1176*96d6407fSRichard Henderson if (rt == 0) { 1177*96d6407fSRichard Henderson gen_helper_loaded_fr0(cpu_env); 1178*96d6407fSRichard Henderson } 1179*96d6407fSRichard Henderson 1180*96d6407fSRichard Henderson return nullify_end(ctx, NO_EXIT); 1181*96d6407fSRichard Henderson } 1182*96d6407fSRichard Henderson 1183*96d6407fSRichard Henderson static ExitStatus do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1184*96d6407fSRichard Henderson target_long disp, int modify, TCGMemOp mop) 1185*96d6407fSRichard Henderson { 1186*96d6407fSRichard Henderson nullify_over(ctx); 1187*96d6407fSRichard Henderson do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop); 1188*96d6407fSRichard Henderson return nullify_end(ctx, NO_EXIT); 1189*96d6407fSRichard Henderson } 1190*96d6407fSRichard Henderson 1191*96d6407fSRichard Henderson static ExitStatus do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1192*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1193*96d6407fSRichard Henderson int modify) 1194*96d6407fSRichard Henderson { 1195*96d6407fSRichard Henderson TCGv_i32 tmp; 1196*96d6407fSRichard Henderson 1197*96d6407fSRichard Henderson nullify_over(ctx); 1198*96d6407fSRichard Henderson 1199*96d6407fSRichard Henderson tmp = load_frw_i32(rt); 1200*96d6407fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL); 1201*96d6407fSRichard Henderson tcg_temp_free_i32(tmp); 1202*96d6407fSRichard Henderson 1203*96d6407fSRichard Henderson return nullify_end(ctx, NO_EXIT); 1204*96d6407fSRichard Henderson } 1205*96d6407fSRichard Henderson 1206*96d6407fSRichard Henderson static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1207*96d6407fSRichard Henderson unsigned rx, int scale, target_long disp, 1208*96d6407fSRichard Henderson int modify) 1209*96d6407fSRichard Henderson { 1210*96d6407fSRichard Henderson TCGv_i64 tmp; 1211*96d6407fSRichard Henderson 1212*96d6407fSRichard Henderson nullify_over(ctx); 1213*96d6407fSRichard Henderson 1214*96d6407fSRichard Henderson tmp = load_frd(rt); 1215*96d6407fSRichard Henderson do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ); 1216*96d6407fSRichard Henderson tcg_temp_free_i64(tmp); 1217*96d6407fSRichard Henderson 1218*96d6407fSRichard Henderson return nullify_end(ctx, NO_EXIT); 1219*96d6407fSRichard Henderson } 1220*96d6407fSRichard Henderson 122198cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 122298cd9ca7SRichard Henderson have already had nullification handled. */ 122398cd9ca7SRichard Henderson static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest, 122498cd9ca7SRichard Henderson unsigned link, bool is_n) 122598cd9ca7SRichard Henderson { 122698cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 122798cd9ca7SRichard Henderson if (link != 0) { 122898cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 122998cd9ca7SRichard Henderson } 123098cd9ca7SRichard Henderson ctx->iaoq_n = dest; 123198cd9ca7SRichard Henderson if (is_n) { 123298cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 123398cd9ca7SRichard Henderson } 123498cd9ca7SRichard Henderson return NO_EXIT; 123598cd9ca7SRichard Henderson } else { 123698cd9ca7SRichard Henderson nullify_over(ctx); 123798cd9ca7SRichard Henderson 123898cd9ca7SRichard Henderson if (link != 0) { 123998cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 124098cd9ca7SRichard Henderson } 124198cd9ca7SRichard Henderson 124298cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 124398cd9ca7SRichard Henderson nullify_set(ctx, 0); 124498cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 124598cd9ca7SRichard Henderson } else { 124698cd9ca7SRichard Henderson nullify_set(ctx, is_n); 124798cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 124898cd9ca7SRichard Henderson } 124998cd9ca7SRichard Henderson 125098cd9ca7SRichard Henderson nullify_end(ctx, NO_EXIT); 125198cd9ca7SRichard Henderson 125298cd9ca7SRichard Henderson nullify_set(ctx, 0); 125398cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 125498cd9ca7SRichard Henderson return EXIT_GOTO_TB; 125598cd9ca7SRichard Henderson } 125698cd9ca7SRichard Henderson } 125798cd9ca7SRichard Henderson 125898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 125998cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 126098cd9ca7SRichard Henderson static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n, 126198cd9ca7SRichard Henderson DisasCond *cond) 126298cd9ca7SRichard Henderson { 126398cd9ca7SRichard Henderson target_ulong dest = iaoq_dest(ctx, disp); 126498cd9ca7SRichard Henderson TCGLabel *taken = NULL; 126598cd9ca7SRichard Henderson TCGCond c = cond->c; 126698cd9ca7SRichard Henderson int which = 0; 126798cd9ca7SRichard Henderson bool n; 126898cd9ca7SRichard Henderson 126998cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 127098cd9ca7SRichard Henderson 127198cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 127298cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 127398cd9ca7SRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 127498cd9ca7SRichard Henderson } 127598cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 127698cd9ca7SRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 127798cd9ca7SRichard Henderson } 127898cd9ca7SRichard Henderson 127998cd9ca7SRichard Henderson taken = gen_new_label(); 128098cd9ca7SRichard Henderson cond_prep(cond); 128198cd9ca7SRichard Henderson tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken); 128298cd9ca7SRichard Henderson cond_free(cond); 128398cd9ca7SRichard Henderson 128498cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 128598cd9ca7SRichard Henderson n = is_n && disp < 0; 128698cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 128798cd9ca7SRichard Henderson nullify_set(ctx, 0); 128898cd9ca7SRichard Henderson gen_goto_tb(ctx, which++, ctx->iaoq_n, ctx->iaoq_n + 4); 128998cd9ca7SRichard Henderson } else { 129098cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 129198cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 129298cd9ca7SRichard Henderson ctx->null_lab = NULL; 129398cd9ca7SRichard Henderson } 129498cd9ca7SRichard Henderson nullify_set(ctx, n); 129598cd9ca7SRichard Henderson gen_goto_tb(ctx, which++, ctx->iaoq_b, ctx->iaoq_n); 129698cd9ca7SRichard Henderson } 129798cd9ca7SRichard Henderson 129898cd9ca7SRichard Henderson gen_set_label(taken); 129998cd9ca7SRichard Henderson 130098cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 130198cd9ca7SRichard Henderson n = is_n && disp >= 0; 130298cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 130398cd9ca7SRichard Henderson nullify_set(ctx, 0); 130498cd9ca7SRichard Henderson gen_goto_tb(ctx, which++, dest, dest + 4); 130598cd9ca7SRichard Henderson } else { 130698cd9ca7SRichard Henderson nullify_set(ctx, n); 130798cd9ca7SRichard Henderson gen_goto_tb(ctx, which++, ctx->iaoq_b, dest); 130898cd9ca7SRichard Henderson } 130998cd9ca7SRichard Henderson 131098cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 131198cd9ca7SRichard Henderson if (ctx->null_lab) { 131298cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 131398cd9ca7SRichard Henderson ctx->null_lab = NULL; 131498cd9ca7SRichard Henderson if (which < 2) { 131598cd9ca7SRichard Henderson nullify_set(ctx, 0); 131698cd9ca7SRichard Henderson gen_goto_tb(ctx, which, ctx->iaoq_b, ctx->iaoq_n); 131798cd9ca7SRichard Henderson return EXIT_GOTO_TB; 131898cd9ca7SRichard Henderson } else { 131998cd9ca7SRichard Henderson return EXIT_IAQ_N_STALE; 132098cd9ca7SRichard Henderson } 132198cd9ca7SRichard Henderson } else { 132298cd9ca7SRichard Henderson return EXIT_GOTO_TB; 132398cd9ca7SRichard Henderson } 132498cd9ca7SRichard Henderson } 132598cd9ca7SRichard Henderson 132698cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 132798cd9ca7SRichard Henderson nullification of the branch itself. */ 132898cd9ca7SRichard Henderson static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest, 132998cd9ca7SRichard Henderson unsigned link, bool is_n) 133098cd9ca7SRichard Henderson { 133198cd9ca7SRichard Henderson TCGv a0, a1, next, tmp; 133298cd9ca7SRichard Henderson TCGCond c; 133398cd9ca7SRichard Henderson 133498cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 133598cd9ca7SRichard Henderson 133698cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 133798cd9ca7SRichard Henderson if (link != 0) { 133898cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 133998cd9ca7SRichard Henderson } 134098cd9ca7SRichard Henderson next = get_temp(ctx); 134198cd9ca7SRichard Henderson tcg_gen_mov_tl(next, dest); 134298cd9ca7SRichard Henderson ctx->iaoq_n = -1; 134398cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 134498cd9ca7SRichard Henderson if (is_n) { 134598cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 134698cd9ca7SRichard Henderson } 134798cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 134898cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 134998cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 135098cd9ca7SRichard Henderson tracepoint in effect). Since the exit_tb that we must use 135198cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 135298cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 135398cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 135498cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 135598cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 135698cd9ca7SRichard Henderson 135798cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 135898cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 135998cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 136098cd9ca7SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, dest); 136198cd9ca7SRichard Henderson tcg_gen_addi_tl(cpu_iaoq_b, dest, 4); 136298cd9ca7SRichard Henderson 136398cd9ca7SRichard Henderson nullify_over(ctx); 136498cd9ca7SRichard Henderson if (link != 0) { 136598cd9ca7SRichard Henderson tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n); 136698cd9ca7SRichard Henderson } 136798cd9ca7SRichard Henderson tcg_gen_exit_tb(0); 136898cd9ca7SRichard Henderson return nullify_end(ctx, NO_EXIT); 136998cd9ca7SRichard Henderson } else { 137098cd9ca7SRichard Henderson cond_prep(&ctx->null_cond); 137198cd9ca7SRichard Henderson c = ctx->null_cond.c; 137298cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 137398cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 137498cd9ca7SRichard Henderson 137598cd9ca7SRichard Henderson tmp = tcg_temp_new(); 137698cd9ca7SRichard Henderson next = get_temp(ctx); 137798cd9ca7SRichard Henderson 137898cd9ca7SRichard Henderson copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var); 137998cd9ca7SRichard Henderson tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest); 138098cd9ca7SRichard Henderson ctx->iaoq_n = -1; 138198cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 138298cd9ca7SRichard Henderson 138398cd9ca7SRichard Henderson if (link != 0) { 138498cd9ca7SRichard Henderson tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 138598cd9ca7SRichard Henderson } 138698cd9ca7SRichard Henderson 138798cd9ca7SRichard Henderson if (is_n) { 138898cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 138998cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 139098cd9ca7SRichard Henderson to the branch. */ 139198cd9ca7SRichard Henderson tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1); 139298cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 139398cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 139498cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 139598cd9ca7SRichard Henderson } else { 139698cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 139798cd9ca7SRichard Henderson } 139898cd9ca7SRichard Henderson } 139998cd9ca7SRichard Henderson 140098cd9ca7SRichard Henderson return NO_EXIT; 140198cd9ca7SRichard Henderson } 140298cd9ca7SRichard Henderson 14037ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 14047ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 14057ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 14067ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 14077ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 14087ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 14097ad439dfSRichard Henderson aforementioned BE. */ 14107ad439dfSRichard Henderson static ExitStatus do_page_zero(DisasContext *ctx) 14117ad439dfSRichard Henderson { 14127ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 14137ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 14147ad439dfSRichard Henderson next insn within the privilaged page. */ 14157ad439dfSRichard Henderson switch (ctx->null_cond.c) { 14167ad439dfSRichard Henderson case TCG_COND_NEVER: 14177ad439dfSRichard Henderson break; 14187ad439dfSRichard Henderson case TCG_COND_ALWAYS: 14197ad439dfSRichard Henderson tcg_gen_movi_tl(cpu_psw_n, 0); 14207ad439dfSRichard Henderson goto do_sigill; 14217ad439dfSRichard Henderson default: 14227ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 14237ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 14247ad439dfSRichard Henderson g_assert_not_reached(); 14257ad439dfSRichard Henderson } 14267ad439dfSRichard Henderson 14277ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 14287ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 14297ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 14307ad439dfSRichard Henderson under such conditions. */ 14317ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 14327ad439dfSRichard Henderson goto do_sigill; 14337ad439dfSRichard Henderson } 14347ad439dfSRichard Henderson 14357ad439dfSRichard Henderson switch (ctx->iaoq_f) { 14367ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 14377ad439dfSRichard Henderson gen_excp_1(EXCP_SIGSEGV); 14387ad439dfSRichard Henderson return EXIT_NORETURN; 14397ad439dfSRichard Henderson 14407ad439dfSRichard Henderson case 0xb0: /* LWS */ 14417ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 14427ad439dfSRichard Henderson return EXIT_NORETURN; 14437ad439dfSRichard Henderson 14447ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 14457ad439dfSRichard Henderson tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]); 14467ad439dfSRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]); 14477ad439dfSRichard Henderson tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4); 14487ad439dfSRichard Henderson return EXIT_IAQ_N_UPDATED; 14497ad439dfSRichard Henderson 14507ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 14517ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 14527ad439dfSRichard Henderson return EXIT_NORETURN; 14537ad439dfSRichard Henderson 14547ad439dfSRichard Henderson default: 14557ad439dfSRichard Henderson do_sigill: 14567ad439dfSRichard Henderson gen_excp_1(EXCP_SIGILL); 14577ad439dfSRichard Henderson return EXIT_NORETURN; 14587ad439dfSRichard Henderson } 14597ad439dfSRichard Henderson } 14607ad439dfSRichard Henderson 1461b2167459SRichard Henderson static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn, 1462b2167459SRichard Henderson const DisasInsn *di) 1463b2167459SRichard Henderson { 1464b2167459SRichard Henderson cond_free(&ctx->null_cond); 1465b2167459SRichard Henderson return NO_EXIT; 1466b2167459SRichard Henderson } 1467b2167459SRichard Henderson 1468b2167459SRichard Henderson static ExitStatus trans_add(DisasContext *ctx, uint32_t insn, 1469b2167459SRichard Henderson const DisasInsn *di) 1470b2167459SRichard Henderson { 1471b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1472b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1473b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1474b2167459SRichard Henderson unsigned ext = extract32(insn, 8, 4); 1475b2167459SRichard Henderson unsigned shift = extract32(insn, 6, 2); 1476b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1477b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1478b2167459SRichard Henderson bool is_c = false; 1479b2167459SRichard Henderson bool is_l = false; 1480b2167459SRichard Henderson bool is_tc = false; 1481b2167459SRichard Henderson bool is_tsv = false; 1482b2167459SRichard Henderson ExitStatus ret; 1483b2167459SRichard Henderson 1484b2167459SRichard Henderson switch (ext) { 1485b2167459SRichard Henderson case 0x6: /* ADD, SHLADD */ 1486b2167459SRichard Henderson break; 1487b2167459SRichard Henderson case 0xa: /* ADD,L, SHLADD,L */ 1488b2167459SRichard Henderson is_l = true; 1489b2167459SRichard Henderson break; 1490b2167459SRichard Henderson case 0xe: /* ADD,TSV, SHLADD,TSV (1) */ 1491b2167459SRichard Henderson is_tsv = true; 1492b2167459SRichard Henderson break; 1493b2167459SRichard Henderson case 0x7: /* ADD,C */ 1494b2167459SRichard Henderson is_c = true; 1495b2167459SRichard Henderson break; 1496b2167459SRichard Henderson case 0xf: /* ADD,C,TSV */ 1497b2167459SRichard Henderson is_c = is_tsv = true; 1498b2167459SRichard Henderson break; 1499b2167459SRichard Henderson default: 1500b2167459SRichard Henderson return gen_illegal(ctx); 1501b2167459SRichard Henderson } 1502b2167459SRichard Henderson 1503b2167459SRichard Henderson if (cf) { 1504b2167459SRichard Henderson nullify_over(ctx); 1505b2167459SRichard Henderson } 1506b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1507b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1508b2167459SRichard Henderson ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf); 1509b2167459SRichard Henderson return nullify_end(ctx, ret); 1510b2167459SRichard Henderson } 1511b2167459SRichard Henderson 1512b2167459SRichard Henderson static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn, 1513b2167459SRichard Henderson const DisasInsn *di) 1514b2167459SRichard Henderson { 1515b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1516b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1517b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1518b2167459SRichard Henderson unsigned ext = extract32(insn, 6, 6); 1519b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1520b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1521b2167459SRichard Henderson bool is_b = false; 1522b2167459SRichard Henderson bool is_tc = false; 1523b2167459SRichard Henderson bool is_tsv = false; 1524b2167459SRichard Henderson ExitStatus ret; 1525b2167459SRichard Henderson 1526b2167459SRichard Henderson switch (ext) { 1527b2167459SRichard Henderson case 0x10: /* SUB */ 1528b2167459SRichard Henderson break; 1529b2167459SRichard Henderson case 0x30: /* SUB,TSV */ 1530b2167459SRichard Henderson is_tsv = true; 1531b2167459SRichard Henderson break; 1532b2167459SRichard Henderson case 0x14: /* SUB,B */ 1533b2167459SRichard Henderson is_b = true; 1534b2167459SRichard Henderson break; 1535b2167459SRichard Henderson case 0x34: /* SUB,B,TSV */ 1536b2167459SRichard Henderson is_b = is_tsv = true; 1537b2167459SRichard Henderson break; 1538b2167459SRichard Henderson case 0x13: /* SUB,TC */ 1539b2167459SRichard Henderson is_tc = true; 1540b2167459SRichard Henderson break; 1541b2167459SRichard Henderson case 0x33: /* SUB,TSV,TC */ 1542b2167459SRichard Henderson is_tc = is_tsv = true; 1543b2167459SRichard Henderson break; 1544b2167459SRichard Henderson default: 1545b2167459SRichard Henderson return gen_illegal(ctx); 1546b2167459SRichard Henderson } 1547b2167459SRichard Henderson 1548b2167459SRichard Henderson if (cf) { 1549b2167459SRichard Henderson nullify_over(ctx); 1550b2167459SRichard Henderson } 1551b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1552b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1553b2167459SRichard Henderson ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf); 1554b2167459SRichard Henderson return nullify_end(ctx, ret); 1555b2167459SRichard Henderson } 1556b2167459SRichard Henderson 1557b2167459SRichard Henderson static ExitStatus trans_log(DisasContext *ctx, uint32_t insn, 1558b2167459SRichard Henderson const DisasInsn *di) 1559b2167459SRichard Henderson { 1560b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1561b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1562b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1563b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1564b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1565b2167459SRichard Henderson ExitStatus ret; 1566b2167459SRichard Henderson 1567b2167459SRichard Henderson if (cf) { 1568b2167459SRichard Henderson nullify_over(ctx); 1569b2167459SRichard Henderson } 1570b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1571b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1572b2167459SRichard Henderson ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f_ttt); 1573b2167459SRichard Henderson return nullify_end(ctx, ret); 1574b2167459SRichard Henderson } 1575b2167459SRichard Henderson 1576b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */ 1577b2167459SRichard Henderson static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn, 1578b2167459SRichard Henderson const DisasInsn *di) 1579b2167459SRichard Henderson { 1580b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1581b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1582b2167459SRichard Henderson 1583b2167459SRichard Henderson if (r1 == 0) { 1584b2167459SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 1585b2167459SRichard Henderson tcg_gen_movi_tl(dest, 0); 1586b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1587b2167459SRichard Henderson } else { 1588b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 1589b2167459SRichard Henderson } 1590b2167459SRichard Henderson cond_free(&ctx->null_cond); 1591b2167459SRichard Henderson return NO_EXIT; 1592b2167459SRichard Henderson } 1593b2167459SRichard Henderson 1594b2167459SRichard Henderson static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn, 1595b2167459SRichard Henderson const DisasInsn *di) 1596b2167459SRichard Henderson { 1597b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1598b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1599b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1600b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1601b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1602b2167459SRichard Henderson ExitStatus ret; 1603b2167459SRichard Henderson 1604b2167459SRichard Henderson if (cf) { 1605b2167459SRichard Henderson nullify_over(ctx); 1606b2167459SRichard Henderson } 1607b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1608b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1609b2167459SRichard Henderson ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf); 1610b2167459SRichard Henderson return nullify_end(ctx, ret); 1611b2167459SRichard Henderson } 1612b2167459SRichard Henderson 1613b2167459SRichard Henderson static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn, 1614b2167459SRichard Henderson const DisasInsn *di) 1615b2167459SRichard Henderson { 1616b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1617b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1618b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1619b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1620b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1621b2167459SRichard Henderson ExitStatus ret; 1622b2167459SRichard Henderson 1623b2167459SRichard Henderson if (cf) { 1624b2167459SRichard Henderson nullify_over(ctx); 1625b2167459SRichard Henderson } 1626b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1627b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1628b2167459SRichard Henderson ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl); 1629b2167459SRichard Henderson return nullify_end(ctx, ret); 1630b2167459SRichard Henderson } 1631b2167459SRichard Henderson 1632b2167459SRichard Henderson static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn, 1633b2167459SRichard Henderson const DisasInsn *di) 1634b2167459SRichard Henderson { 1635b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1636b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1637b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1638b2167459SRichard Henderson unsigned is_tc = extract32(insn, 6, 1); 1639b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1640b2167459SRichard Henderson TCGv tcg_r1, tcg_r2, tmp; 1641b2167459SRichard Henderson ExitStatus ret; 1642b2167459SRichard Henderson 1643b2167459SRichard Henderson if (cf) { 1644b2167459SRichard Henderson nullify_over(ctx); 1645b2167459SRichard Henderson } 1646b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1647b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1648b2167459SRichard Henderson tmp = get_temp(ctx); 1649b2167459SRichard Henderson tcg_gen_not_tl(tmp, tcg_r2); 1650b2167459SRichard Henderson ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl); 1651b2167459SRichard Henderson return nullify_end(ctx, ret); 1652b2167459SRichard Henderson } 1653b2167459SRichard Henderson 1654b2167459SRichard Henderson static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn, 1655b2167459SRichard Henderson const DisasInsn *di) 1656b2167459SRichard Henderson { 1657b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1658b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1659b2167459SRichard Henderson unsigned is_i = extract32(insn, 6, 1); 1660b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1661b2167459SRichard Henderson TCGv tmp; 1662b2167459SRichard Henderson ExitStatus ret; 1663b2167459SRichard Henderson 1664b2167459SRichard Henderson nullify_over(ctx); 1665b2167459SRichard Henderson 1666b2167459SRichard Henderson tmp = get_temp(ctx); 1667b2167459SRichard Henderson tcg_gen_shri_tl(tmp, cpu_psw_cb, 3); 1668b2167459SRichard Henderson if (!is_i) { 1669b2167459SRichard Henderson tcg_gen_not_tl(tmp, tmp); 1670b2167459SRichard Henderson } 1671b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x11111111); 1672b2167459SRichard Henderson tcg_gen_muli_tl(tmp, tmp, 6); 1673b2167459SRichard Henderson ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false, 1674b2167459SRichard Henderson is_i ? tcg_gen_add_tl : tcg_gen_sub_tl); 1675b2167459SRichard Henderson 1676b2167459SRichard Henderson return nullify_end(ctx, ret); 1677b2167459SRichard Henderson } 1678b2167459SRichard Henderson 1679b2167459SRichard Henderson static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn, 1680b2167459SRichard Henderson const DisasInsn *di) 1681b2167459SRichard Henderson { 1682b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1683b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1684b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1685b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1686b2167459SRichard Henderson TCGv dest, add1, add2, addc, zero, in1, in2; 1687b2167459SRichard Henderson 1688b2167459SRichard Henderson nullify_over(ctx); 1689b2167459SRichard Henderson 1690b2167459SRichard Henderson in1 = load_gpr(ctx, r1); 1691b2167459SRichard Henderson in2 = load_gpr(ctx, r2); 1692b2167459SRichard Henderson 1693b2167459SRichard Henderson add1 = tcg_temp_new(); 1694b2167459SRichard Henderson add2 = tcg_temp_new(); 1695b2167459SRichard Henderson addc = tcg_temp_new(); 1696b2167459SRichard Henderson dest = tcg_temp_new(); 1697b2167459SRichard Henderson zero = tcg_const_tl(0); 1698b2167459SRichard Henderson 1699b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 1700b2167459SRichard Henderson tcg_gen_add_tl(add1, in1, in1); 1701b2167459SRichard Henderson tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb); 1702b2167459SRichard Henderson 1703b2167459SRichard Henderson /* Add or subtract R2, depending on PSW[V]. Proper computation of 1704b2167459SRichard Henderson carry{8} requires that we subtract via + ~R2 + 1, as described in 1705b2167459SRichard Henderson the manual. By extracting and masking V, we can produce the 1706b2167459SRichard Henderson proper inputs to the addition without movcond. */ 1707b2167459SRichard Henderson tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1); 1708b2167459SRichard Henderson tcg_gen_xor_tl(add2, in2, addc); 1709b2167459SRichard Henderson tcg_gen_andi_tl(addc, addc, 1); 1710b2167459SRichard Henderson /* ??? This is only correct for 32-bit. */ 1711b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero); 1712b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero); 1713b2167459SRichard Henderson 1714b2167459SRichard Henderson tcg_temp_free(addc); 1715b2167459SRichard Henderson tcg_temp_free(zero); 1716b2167459SRichard Henderson 1717b2167459SRichard Henderson /* Write back the result register. */ 1718b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1719b2167459SRichard Henderson 1720b2167459SRichard Henderson /* Write back PSW[CB]. */ 1721b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_cb, add1, add2); 1722b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest); 1723b2167459SRichard Henderson 1724b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 1725b2167459SRichard Henderson tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb); 1726b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2); 1727b2167459SRichard Henderson 1728b2167459SRichard Henderson /* Install the new nullification. */ 1729b2167459SRichard Henderson if (cf) { 1730b2167459SRichard Henderson TCGv sv; 1731b2167459SRichard Henderson TCGV_UNUSED(sv); 1732b2167459SRichard Henderson if (cf >> 1 == 6) { 1733b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 1734b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 1735b2167459SRichard Henderson } 1736b2167459SRichard Henderson ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv); 1737b2167459SRichard Henderson } 1738b2167459SRichard Henderson 1739b2167459SRichard Henderson tcg_temp_free(add1); 1740b2167459SRichard Henderson tcg_temp_free(add2); 1741b2167459SRichard Henderson tcg_temp_free(dest); 1742b2167459SRichard Henderson 1743b2167459SRichard Henderson return nullify_end(ctx, NO_EXIT); 1744b2167459SRichard Henderson } 1745b2167459SRichard Henderson 1746b2167459SRichard Henderson static const DisasInsn table_arith_log[] = { 1747b2167459SRichard Henderson { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */ 1748b2167459SRichard Henderson { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */ 1749b2167459SRichard Henderson { 0x08000000u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_andc_tl }, 1750b2167459SRichard Henderson { 0x08000200u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_and_tl }, 1751b2167459SRichard Henderson { 0x08000240u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_or_tl }, 1752b2167459SRichard Henderson { 0x08000280u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_xor_tl }, 1753b2167459SRichard Henderson { 0x08000880u, 0xfc000fe0u, trans_cmpclr }, 1754b2167459SRichard Henderson { 0x08000380u, 0xfc000fe0u, trans_uxor }, 1755b2167459SRichard Henderson { 0x08000980u, 0xfc000fa0u, trans_uaddcm }, 1756b2167459SRichard Henderson { 0x08000b80u, 0xfc1f0fa0u, trans_dcor }, 1757b2167459SRichard Henderson { 0x08000440u, 0xfc000fe0u, trans_ds }, 1758b2167459SRichard Henderson { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */ 1759b2167459SRichard Henderson { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */ 1760b2167459SRichard Henderson { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */ 1761b2167459SRichard Henderson { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */ 1762b2167459SRichard Henderson }; 1763b2167459SRichard Henderson 1764b2167459SRichard Henderson static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn) 1765b2167459SRichard Henderson { 1766b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1767b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 1768b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1769b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1770b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1771b2167459SRichard Henderson unsigned o1 = extract32(insn, 26, 1); 1772b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1773b2167459SRichard Henderson ExitStatus ret; 1774b2167459SRichard Henderson 1775b2167459SRichard Henderson if (cf) { 1776b2167459SRichard Henderson nullify_over(ctx); 1777b2167459SRichard Henderson } 1778b2167459SRichard Henderson 1779b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1780b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1781b2167459SRichard Henderson ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf); 1782b2167459SRichard Henderson 1783b2167459SRichard Henderson return nullify_end(ctx, ret); 1784b2167459SRichard Henderson } 1785b2167459SRichard Henderson 1786b2167459SRichard Henderson static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn) 1787b2167459SRichard Henderson { 1788b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1789b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 1790b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1791b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1792b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1793b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1794b2167459SRichard Henderson ExitStatus ret; 1795b2167459SRichard Henderson 1796b2167459SRichard Henderson if (cf) { 1797b2167459SRichard Henderson nullify_over(ctx); 1798b2167459SRichard Henderson } 1799b2167459SRichard Henderson 1800b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1801b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1802b2167459SRichard Henderson ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf); 1803b2167459SRichard Henderson 1804b2167459SRichard Henderson return nullify_end(ctx, ret); 1805b2167459SRichard Henderson } 1806b2167459SRichard Henderson 1807b2167459SRichard Henderson static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn) 1808b2167459SRichard Henderson { 1809b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1810b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1811b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1812b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1813b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1814b2167459SRichard Henderson ExitStatus ret; 1815b2167459SRichard Henderson 1816b2167459SRichard Henderson if (cf) { 1817b2167459SRichard Henderson nullify_over(ctx); 1818b2167459SRichard Henderson } 1819b2167459SRichard Henderson 1820b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1821b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1822b2167459SRichard Henderson ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf); 1823b2167459SRichard Henderson 1824b2167459SRichard Henderson return nullify_end(ctx, ret); 1825b2167459SRichard Henderson } 1826b2167459SRichard Henderson 1827*96d6407fSRichard Henderson static ExitStatus trans_ld_idx_i(DisasContext *ctx, uint32_t insn, 1828*96d6407fSRichard Henderson const DisasInsn *di) 1829*96d6407fSRichard Henderson { 1830*96d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 1831*96d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 1832*96d6407fSRichard Henderson unsigned sz = extract32(insn, 6, 2); 1833*96d6407fSRichard Henderson unsigned a = extract32(insn, 13, 1); 1834*96d6407fSRichard Henderson int disp = low_sextract(insn, 16, 5); 1835*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 1836*96d6407fSRichard Henderson int modify = (m ? (a ? -1 : 1) : 0); 1837*96d6407fSRichard Henderson TCGMemOp mop = MO_TE | sz; 1838*96d6407fSRichard Henderson 1839*96d6407fSRichard Henderson return do_load(ctx, rt, rb, 0, 0, disp, modify, mop); 1840*96d6407fSRichard Henderson } 1841*96d6407fSRichard Henderson 1842*96d6407fSRichard Henderson static ExitStatus trans_ld_idx_x(DisasContext *ctx, uint32_t insn, 1843*96d6407fSRichard Henderson const DisasInsn *di) 1844*96d6407fSRichard Henderson { 1845*96d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 1846*96d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 1847*96d6407fSRichard Henderson unsigned sz = extract32(insn, 6, 2); 1848*96d6407fSRichard Henderson unsigned u = extract32(insn, 13, 1); 1849*96d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 1850*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 1851*96d6407fSRichard Henderson TCGMemOp mop = MO_TE | sz; 1852*96d6407fSRichard Henderson 1853*96d6407fSRichard Henderson return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop); 1854*96d6407fSRichard Henderson } 1855*96d6407fSRichard Henderson 1856*96d6407fSRichard Henderson static ExitStatus trans_st_idx_i(DisasContext *ctx, uint32_t insn, 1857*96d6407fSRichard Henderson const DisasInsn *di) 1858*96d6407fSRichard Henderson { 1859*96d6407fSRichard Henderson int disp = low_sextract(insn, 0, 5); 1860*96d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 1861*96d6407fSRichard Henderson unsigned sz = extract32(insn, 6, 2); 1862*96d6407fSRichard Henderson unsigned a = extract32(insn, 13, 1); 1863*96d6407fSRichard Henderson unsigned rr = extract32(insn, 16, 5); 1864*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 1865*96d6407fSRichard Henderson int modify = (m ? (a ? -1 : 1) : 0); 1866*96d6407fSRichard Henderson TCGMemOp mop = MO_TE | sz; 1867*96d6407fSRichard Henderson 1868*96d6407fSRichard Henderson return do_store(ctx, rr, rb, disp, modify, mop); 1869*96d6407fSRichard Henderson } 1870*96d6407fSRichard Henderson 1871*96d6407fSRichard Henderson static ExitStatus trans_ldcw(DisasContext *ctx, uint32_t insn, 1872*96d6407fSRichard Henderson const DisasInsn *di) 1873*96d6407fSRichard Henderson { 1874*96d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 1875*96d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 1876*96d6407fSRichard Henderson unsigned i = extract32(insn, 12, 1); 1877*96d6407fSRichard Henderson unsigned au = extract32(insn, 13, 1); 1878*96d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 1879*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 1880*96d6407fSRichard Henderson TCGMemOp mop = MO_TEUL | MO_ALIGN_16; 1881*96d6407fSRichard Henderson TCGv zero, addr, base, dest; 1882*96d6407fSRichard Henderson int modify, disp = 0, scale = 0; 1883*96d6407fSRichard Henderson 1884*96d6407fSRichard Henderson nullify_over(ctx); 1885*96d6407fSRichard Henderson 1886*96d6407fSRichard Henderson /* ??? Share more code with do_load and do_load_{32,64}. */ 1887*96d6407fSRichard Henderson 1888*96d6407fSRichard Henderson if (i) { 1889*96d6407fSRichard Henderson modify = (m ? (au ? -1 : 1) : 0); 1890*96d6407fSRichard Henderson disp = low_sextract(rx, 0, 5); 1891*96d6407fSRichard Henderson rx = 0; 1892*96d6407fSRichard Henderson } else { 1893*96d6407fSRichard Henderson modify = m; 1894*96d6407fSRichard Henderson if (au) { 1895*96d6407fSRichard Henderson scale = mop & MO_SIZE; 1896*96d6407fSRichard Henderson } 1897*96d6407fSRichard Henderson } 1898*96d6407fSRichard Henderson if (modify) { 1899*96d6407fSRichard Henderson /* Base register modification. Make sure if RT == RB, we see 1900*96d6407fSRichard Henderson the result of the load. */ 1901*96d6407fSRichard Henderson dest = get_temp(ctx); 1902*96d6407fSRichard Henderson } else { 1903*96d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 1904*96d6407fSRichard Henderson } 1905*96d6407fSRichard Henderson 1906*96d6407fSRichard Henderson addr = tcg_temp_new(); 1907*96d6407fSRichard Henderson base = load_gpr(ctx, rb); 1908*96d6407fSRichard Henderson if (rx) { 1909*96d6407fSRichard Henderson tcg_gen_shli_tl(addr, cpu_gr[rx], scale); 1910*96d6407fSRichard Henderson tcg_gen_add_tl(addr, addr, base); 1911*96d6407fSRichard Henderson } else { 1912*96d6407fSRichard Henderson tcg_gen_addi_tl(addr, base, disp); 1913*96d6407fSRichard Henderson } 1914*96d6407fSRichard Henderson 1915*96d6407fSRichard Henderson zero = tcg_const_tl(0); 1916*96d6407fSRichard Henderson tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base), 1917*96d6407fSRichard Henderson zero, MMU_USER_IDX, mop); 1918*96d6407fSRichard Henderson if (modify) { 1919*96d6407fSRichard Henderson save_gpr(ctx, rb, addr); 1920*96d6407fSRichard Henderson } 1921*96d6407fSRichard Henderson save_gpr(ctx, rt, dest); 1922*96d6407fSRichard Henderson 1923*96d6407fSRichard Henderson return nullify_end(ctx, NO_EXIT); 1924*96d6407fSRichard Henderson } 1925*96d6407fSRichard Henderson 1926*96d6407fSRichard Henderson static ExitStatus trans_stby(DisasContext *ctx, uint32_t insn, 1927*96d6407fSRichard Henderson const DisasInsn *di) 1928*96d6407fSRichard Henderson { 1929*96d6407fSRichard Henderson target_long disp = low_sextract(insn, 0, 5); 1930*96d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 1931*96d6407fSRichard Henderson unsigned a = extract32(insn, 13, 1); 1932*96d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 1933*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 1934*96d6407fSRichard Henderson TCGv addr, val; 1935*96d6407fSRichard Henderson 1936*96d6407fSRichard Henderson nullify_over(ctx); 1937*96d6407fSRichard Henderson 1938*96d6407fSRichard Henderson addr = tcg_temp_new(); 1939*96d6407fSRichard Henderson if (m || disp == 0) { 1940*96d6407fSRichard Henderson tcg_gen_mov_tl(addr, load_gpr(ctx, rb)); 1941*96d6407fSRichard Henderson } else { 1942*96d6407fSRichard Henderson tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp); 1943*96d6407fSRichard Henderson } 1944*96d6407fSRichard Henderson val = load_gpr(ctx, rt); 1945*96d6407fSRichard Henderson 1946*96d6407fSRichard Henderson if (a) { 1947*96d6407fSRichard Henderson gen_helper_stby_e(cpu_env, addr, val); 1948*96d6407fSRichard Henderson } else { 1949*96d6407fSRichard Henderson gen_helper_stby_b(cpu_env, addr, val); 1950*96d6407fSRichard Henderson } 1951*96d6407fSRichard Henderson 1952*96d6407fSRichard Henderson if (m) { 1953*96d6407fSRichard Henderson tcg_gen_addi_tl(addr, addr, disp); 1954*96d6407fSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1955*96d6407fSRichard Henderson save_gpr(ctx, rb, addr); 1956*96d6407fSRichard Henderson } 1957*96d6407fSRichard Henderson tcg_temp_free(addr); 1958*96d6407fSRichard Henderson 1959*96d6407fSRichard Henderson return nullify_end(ctx, NO_EXIT); 1960*96d6407fSRichard Henderson } 1961*96d6407fSRichard Henderson 1962*96d6407fSRichard Henderson static const DisasInsn table_index_mem[] = { 1963*96d6407fSRichard Henderson { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */ 1964*96d6407fSRichard Henderson { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */ 1965*96d6407fSRichard Henderson { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */ 1966*96d6407fSRichard Henderson { 0x0c0001c0u, 0xfc0003c0, trans_ldcw }, 1967*96d6407fSRichard Henderson { 0x0c001300u, 0xfc0013c0, trans_stby }, 1968*96d6407fSRichard Henderson }; 1969*96d6407fSRichard Henderson 1970b2167459SRichard Henderson static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn) 1971b2167459SRichard Henderson { 1972b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 1973b2167459SRichard Henderson target_long i = assemble_21(insn); 1974b2167459SRichard Henderson TCGv tcg_rt = dest_gpr(ctx, rt); 1975b2167459SRichard Henderson 1976b2167459SRichard Henderson tcg_gen_movi_tl(tcg_rt, i); 1977b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 1978b2167459SRichard Henderson cond_free(&ctx->null_cond); 1979b2167459SRichard Henderson 1980b2167459SRichard Henderson return NO_EXIT; 1981b2167459SRichard Henderson } 1982b2167459SRichard Henderson 1983b2167459SRichard Henderson static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn) 1984b2167459SRichard Henderson { 1985b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 1986b2167459SRichard Henderson target_long i = assemble_21(insn); 1987b2167459SRichard Henderson TCGv tcg_rt = load_gpr(ctx, rt); 1988b2167459SRichard Henderson TCGv tcg_r1 = dest_gpr(ctx, 1); 1989b2167459SRichard Henderson 1990b2167459SRichard Henderson tcg_gen_addi_tl(tcg_r1, tcg_rt, i); 1991b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 1992b2167459SRichard Henderson cond_free(&ctx->null_cond); 1993b2167459SRichard Henderson 1994b2167459SRichard Henderson return NO_EXIT; 1995b2167459SRichard Henderson } 1996b2167459SRichard Henderson 1997b2167459SRichard Henderson static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn) 1998b2167459SRichard Henderson { 1999b2167459SRichard Henderson unsigned rb = extract32(insn, 21, 5); 2000b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2001b2167459SRichard Henderson target_long i = assemble_16(insn); 2002b2167459SRichard Henderson TCGv tcg_rt = dest_gpr(ctx, rt); 2003b2167459SRichard Henderson 2004b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 2005b2167459SRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */ 2006b2167459SRichard Henderson if (rb == 0) { 2007b2167459SRichard Henderson tcg_gen_movi_tl(tcg_rt, i); 2008b2167459SRichard Henderson } else { 2009b2167459SRichard Henderson tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i); 2010b2167459SRichard Henderson } 2011b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 2012b2167459SRichard Henderson cond_free(&ctx->null_cond); 2013b2167459SRichard Henderson 2014b2167459SRichard Henderson return NO_EXIT; 2015b2167459SRichard Henderson } 2016b2167459SRichard Henderson 2017*96d6407fSRichard Henderson static ExitStatus trans_load(DisasContext *ctx, uint32_t insn, 2018*96d6407fSRichard Henderson bool is_mod, TCGMemOp mop) 2019*96d6407fSRichard Henderson { 2020*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 2021*96d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 2022*96d6407fSRichard Henderson target_long i = assemble_16(insn); 2023*96d6407fSRichard Henderson 2024*96d6407fSRichard Henderson return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop); 2025*96d6407fSRichard Henderson } 2026*96d6407fSRichard Henderson 2027*96d6407fSRichard Henderson static ExitStatus trans_load_w(DisasContext *ctx, uint32_t insn) 2028*96d6407fSRichard Henderson { 2029*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 2030*96d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 2031*96d6407fSRichard Henderson target_long i = assemble_16a(insn); 2032*96d6407fSRichard Henderson unsigned ext2 = extract32(insn, 1, 2); 2033*96d6407fSRichard Henderson 2034*96d6407fSRichard Henderson switch (ext2) { 2035*96d6407fSRichard Henderson case 0: 2036*96d6407fSRichard Henderson case 1: 2037*96d6407fSRichard Henderson /* FLDW without modification. */ 2038*96d6407fSRichard Henderson return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0); 2039*96d6407fSRichard Henderson case 2: 2040*96d6407fSRichard Henderson /* LDW with modification. Note that the sign of I selects 2041*96d6407fSRichard Henderson post-dec vs pre-inc. */ 2042*96d6407fSRichard Henderson return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL); 2043*96d6407fSRichard Henderson default: 2044*96d6407fSRichard Henderson return gen_illegal(ctx); 2045*96d6407fSRichard Henderson } 2046*96d6407fSRichard Henderson } 2047*96d6407fSRichard Henderson 2048*96d6407fSRichard Henderson static ExitStatus trans_fload_mod(DisasContext *ctx, uint32_t insn) 2049*96d6407fSRichard Henderson { 2050*96d6407fSRichard Henderson target_long i = assemble_16a(insn); 2051*96d6407fSRichard Henderson unsigned t1 = extract32(insn, 1, 1); 2052*96d6407fSRichard Henderson unsigned a = extract32(insn, 2, 1); 2053*96d6407fSRichard Henderson unsigned t0 = extract32(insn, 16, 5); 2054*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 2055*96d6407fSRichard Henderson 2056*96d6407fSRichard Henderson /* FLDW with modification. */ 2057*96d6407fSRichard Henderson return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1)); 2058*96d6407fSRichard Henderson } 2059*96d6407fSRichard Henderson 2060*96d6407fSRichard Henderson static ExitStatus trans_store(DisasContext *ctx, uint32_t insn, 2061*96d6407fSRichard Henderson bool is_mod, TCGMemOp mop) 2062*96d6407fSRichard Henderson { 2063*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 2064*96d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 2065*96d6407fSRichard Henderson target_long i = assemble_16(insn); 2066*96d6407fSRichard Henderson 2067*96d6407fSRichard Henderson return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop); 2068*96d6407fSRichard Henderson } 2069*96d6407fSRichard Henderson 2070*96d6407fSRichard Henderson static ExitStatus trans_store_w(DisasContext *ctx, uint32_t insn) 2071*96d6407fSRichard Henderson { 2072*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 2073*96d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 2074*96d6407fSRichard Henderson target_long i = assemble_16a(insn); 2075*96d6407fSRichard Henderson unsigned ext2 = extract32(insn, 1, 2); 2076*96d6407fSRichard Henderson 2077*96d6407fSRichard Henderson switch (ext2) { 2078*96d6407fSRichard Henderson case 0: 2079*96d6407fSRichard Henderson case 1: 2080*96d6407fSRichard Henderson /* FSTW without modification. */ 2081*96d6407fSRichard Henderson return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0); 2082*96d6407fSRichard Henderson case 2: 2083*96d6407fSRichard Henderson /* LDW with modification. */ 2084*96d6407fSRichard Henderson return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL); 2085*96d6407fSRichard Henderson default: 2086*96d6407fSRichard Henderson return gen_illegal(ctx); 2087*96d6407fSRichard Henderson } 2088*96d6407fSRichard Henderson } 2089*96d6407fSRichard Henderson 2090*96d6407fSRichard Henderson static ExitStatus trans_fstore_mod(DisasContext *ctx, uint32_t insn) 2091*96d6407fSRichard Henderson { 2092*96d6407fSRichard Henderson target_long i = assemble_16a(insn); 2093*96d6407fSRichard Henderson unsigned t1 = extract32(insn, 1, 1); 2094*96d6407fSRichard Henderson unsigned a = extract32(insn, 2, 1); 2095*96d6407fSRichard Henderson unsigned t0 = extract32(insn, 16, 5); 2096*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 2097*96d6407fSRichard Henderson 2098*96d6407fSRichard Henderson /* FSTW with modification. */ 2099*96d6407fSRichard Henderson return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1)); 2100*96d6407fSRichard Henderson } 2101*96d6407fSRichard Henderson 2102*96d6407fSRichard Henderson static ExitStatus trans_copr_w(DisasContext *ctx, uint32_t insn) 2103*96d6407fSRichard Henderson { 2104*96d6407fSRichard Henderson unsigned t0 = extract32(insn, 0, 5); 2105*96d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 2106*96d6407fSRichard Henderson unsigned t1 = extract32(insn, 6, 1); 2107*96d6407fSRichard Henderson unsigned ext3 = extract32(insn, 7, 3); 2108*96d6407fSRichard Henderson /* unsigned cc = extract32(insn, 10, 2); */ 2109*96d6407fSRichard Henderson unsigned i = extract32(insn, 12, 1); 2110*96d6407fSRichard Henderson unsigned ua = extract32(insn, 13, 1); 2111*96d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 2112*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 2113*96d6407fSRichard Henderson unsigned rt = t1 * 32 + t0; 2114*96d6407fSRichard Henderson int modify = (m ? (ua ? -1 : 1) : 0); 2115*96d6407fSRichard Henderson int disp, scale; 2116*96d6407fSRichard Henderson 2117*96d6407fSRichard Henderson if (i == 0) { 2118*96d6407fSRichard Henderson scale = (ua ? 2 : 0); 2119*96d6407fSRichard Henderson disp = 0; 2120*96d6407fSRichard Henderson modify = m; 2121*96d6407fSRichard Henderson } else { 2122*96d6407fSRichard Henderson disp = low_sextract(rx, 0, 5); 2123*96d6407fSRichard Henderson scale = 0; 2124*96d6407fSRichard Henderson rx = 0; 2125*96d6407fSRichard Henderson modify = (m ? (ua ? -1 : 1) : 0); 2126*96d6407fSRichard Henderson } 2127*96d6407fSRichard Henderson 2128*96d6407fSRichard Henderson switch (ext3) { 2129*96d6407fSRichard Henderson case 0: /* FLDW */ 2130*96d6407fSRichard Henderson return do_floadw(ctx, rt, rb, rx, scale, disp, modify); 2131*96d6407fSRichard Henderson case 4: /* FSTW */ 2132*96d6407fSRichard Henderson return do_fstorew(ctx, rt, rb, rx, scale, disp, modify); 2133*96d6407fSRichard Henderson } 2134*96d6407fSRichard Henderson return gen_illegal(ctx); 2135*96d6407fSRichard Henderson } 2136*96d6407fSRichard Henderson 2137*96d6407fSRichard Henderson static ExitStatus trans_copr_dw(DisasContext *ctx, uint32_t insn) 2138*96d6407fSRichard Henderson { 2139*96d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 2140*96d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 2141*96d6407fSRichard Henderson unsigned ext4 = extract32(insn, 6, 4); 2142*96d6407fSRichard Henderson /* unsigned cc = extract32(insn, 10, 2); */ 2143*96d6407fSRichard Henderson unsigned i = extract32(insn, 12, 1); 2144*96d6407fSRichard Henderson unsigned ua = extract32(insn, 13, 1); 2145*96d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 2146*96d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 2147*96d6407fSRichard Henderson int modify = (m ? (ua ? -1 : 1) : 0); 2148*96d6407fSRichard Henderson int disp, scale; 2149*96d6407fSRichard Henderson 2150*96d6407fSRichard Henderson if (i == 0) { 2151*96d6407fSRichard Henderson scale = (ua ? 3 : 0); 2152*96d6407fSRichard Henderson disp = 0; 2153*96d6407fSRichard Henderson modify = m; 2154*96d6407fSRichard Henderson } else { 2155*96d6407fSRichard Henderson disp = low_sextract(rx, 0, 5); 2156*96d6407fSRichard Henderson scale = 0; 2157*96d6407fSRichard Henderson rx = 0; 2158*96d6407fSRichard Henderson modify = (m ? (ua ? -1 : 1) : 0); 2159*96d6407fSRichard Henderson } 2160*96d6407fSRichard Henderson 2161*96d6407fSRichard Henderson switch (ext4) { 2162*96d6407fSRichard Henderson case 0: /* FLDD */ 2163*96d6407fSRichard Henderson return do_floadd(ctx, rt, rb, rx, scale, disp, modify); 2164*96d6407fSRichard Henderson case 8: /* FSTD */ 2165*96d6407fSRichard Henderson return do_fstored(ctx, rt, rb, rx, scale, disp, modify); 2166*96d6407fSRichard Henderson default: 2167*96d6407fSRichard Henderson return gen_illegal(ctx); 2168*96d6407fSRichard Henderson } 2169*96d6407fSRichard Henderson } 2170*96d6407fSRichard Henderson 217198cd9ca7SRichard Henderson static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn, 217298cd9ca7SRichard Henderson bool is_true, bool is_imm, bool is_dw) 217398cd9ca7SRichard Henderson { 217498cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 217598cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 217698cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 217798cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 217898cd9ca7SRichard Henderson unsigned cf = c * 2 + !is_true; 217998cd9ca7SRichard Henderson TCGv dest, in1, in2, sv; 218098cd9ca7SRichard Henderson DisasCond cond; 218198cd9ca7SRichard Henderson 218298cd9ca7SRichard Henderson nullify_over(ctx); 218398cd9ca7SRichard Henderson 218498cd9ca7SRichard Henderson if (is_imm) { 218598cd9ca7SRichard Henderson in1 = load_const(ctx, low_sextract(insn, 16, 5)); 218698cd9ca7SRichard Henderson } else { 218798cd9ca7SRichard Henderson in1 = load_gpr(ctx, extract32(insn, 16, 5)); 218898cd9ca7SRichard Henderson } 218998cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 219098cd9ca7SRichard Henderson dest = get_temp(ctx); 219198cd9ca7SRichard Henderson 219298cd9ca7SRichard Henderson tcg_gen_sub_tl(dest, in1, in2); 219398cd9ca7SRichard Henderson 219498cd9ca7SRichard Henderson TCGV_UNUSED(sv); 219598cd9ca7SRichard Henderson if (c == 6) { 219698cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 219798cd9ca7SRichard Henderson } 219898cd9ca7SRichard Henderson 219998cd9ca7SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 220098cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 220198cd9ca7SRichard Henderson } 220298cd9ca7SRichard Henderson 220398cd9ca7SRichard Henderson static ExitStatus trans_addb(DisasContext *ctx, uint32_t insn, 220498cd9ca7SRichard Henderson bool is_true, bool is_imm) 220598cd9ca7SRichard Henderson { 220698cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 220798cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 220898cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 220998cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 221098cd9ca7SRichard Henderson unsigned cf = c * 2 + !is_true; 221198cd9ca7SRichard Henderson TCGv dest, in1, in2, sv, cb_msb; 221298cd9ca7SRichard Henderson DisasCond cond; 221398cd9ca7SRichard Henderson 221498cd9ca7SRichard Henderson nullify_over(ctx); 221598cd9ca7SRichard Henderson 221698cd9ca7SRichard Henderson if (is_imm) { 221798cd9ca7SRichard Henderson in1 = load_const(ctx, low_sextract(insn, 16, 5)); 221898cd9ca7SRichard Henderson } else { 221998cd9ca7SRichard Henderson in1 = load_gpr(ctx, extract32(insn, 16, 5)); 222098cd9ca7SRichard Henderson } 222198cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 222298cd9ca7SRichard Henderson dest = dest_gpr(ctx, r); 222398cd9ca7SRichard Henderson TCGV_UNUSED(sv); 222498cd9ca7SRichard Henderson TCGV_UNUSED(cb_msb); 222598cd9ca7SRichard Henderson 222698cd9ca7SRichard Henderson switch (c) { 222798cd9ca7SRichard Henderson default: 222898cd9ca7SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 222998cd9ca7SRichard Henderson break; 223098cd9ca7SRichard Henderson case 4: case 5: 223198cd9ca7SRichard Henderson cb_msb = get_temp(ctx); 223298cd9ca7SRichard Henderson tcg_gen_movi_tl(cb_msb, 0); 223398cd9ca7SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb); 223498cd9ca7SRichard Henderson break; 223598cd9ca7SRichard Henderson case 6: 223698cd9ca7SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 223798cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 223898cd9ca7SRichard Henderson break; 223998cd9ca7SRichard Henderson } 224098cd9ca7SRichard Henderson 224198cd9ca7SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 224298cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 224398cd9ca7SRichard Henderson } 224498cd9ca7SRichard Henderson 224598cd9ca7SRichard Henderson static ExitStatus trans_bb(DisasContext *ctx, uint32_t insn) 224698cd9ca7SRichard Henderson { 224798cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 224898cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 224998cd9ca7SRichard Henderson unsigned c = extract32(insn, 15, 1); 225098cd9ca7SRichard Henderson unsigned r = extract32(insn, 16, 5); 225198cd9ca7SRichard Henderson unsigned p = extract32(insn, 21, 5); 225298cd9ca7SRichard Henderson unsigned i = extract32(insn, 26, 1); 225398cd9ca7SRichard Henderson TCGv tmp, tcg_r; 225498cd9ca7SRichard Henderson DisasCond cond; 225598cd9ca7SRichard Henderson 225698cd9ca7SRichard Henderson nullify_over(ctx); 225798cd9ca7SRichard Henderson 225898cd9ca7SRichard Henderson tmp = tcg_temp_new(); 225998cd9ca7SRichard Henderson tcg_r = load_gpr(ctx, r); 226098cd9ca7SRichard Henderson if (i) { 226198cd9ca7SRichard Henderson tcg_gen_shli_tl(tmp, tcg_r, p); 226298cd9ca7SRichard Henderson } else { 226398cd9ca7SRichard Henderson tcg_gen_shl_tl(tmp, tcg_r, cpu_sar); 226498cd9ca7SRichard Henderson } 226598cd9ca7SRichard Henderson 226698cd9ca7SRichard Henderson cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp); 226798cd9ca7SRichard Henderson tcg_temp_free(tmp); 226898cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 226998cd9ca7SRichard Henderson } 227098cd9ca7SRichard Henderson 227198cd9ca7SRichard Henderson static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm) 227298cd9ca7SRichard Henderson { 227398cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 227498cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 227598cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 227698cd9ca7SRichard Henderson unsigned t = extract32(insn, 16, 5); 227798cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 227898cd9ca7SRichard Henderson TCGv dest; 227998cd9ca7SRichard Henderson DisasCond cond; 228098cd9ca7SRichard Henderson 228198cd9ca7SRichard Henderson nullify_over(ctx); 228298cd9ca7SRichard Henderson 228398cd9ca7SRichard Henderson dest = dest_gpr(ctx, r); 228498cd9ca7SRichard Henderson if (is_imm) { 228598cd9ca7SRichard Henderson tcg_gen_movi_tl(dest, low_sextract(t, 0, 5)); 228698cd9ca7SRichard Henderson } else if (t == 0) { 228798cd9ca7SRichard Henderson tcg_gen_movi_tl(dest, 0); 228898cd9ca7SRichard Henderson } else { 228998cd9ca7SRichard Henderson tcg_gen_mov_tl(dest, cpu_gr[t]); 229098cd9ca7SRichard Henderson } 229198cd9ca7SRichard Henderson 229298cd9ca7SRichard Henderson cond = do_sed_cond(c, dest); 229398cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 229498cd9ca7SRichard Henderson } 229598cd9ca7SRichard Henderson 22960b1347d2SRichard Henderson static ExitStatus trans_shrpw_sar(DisasContext *ctx, uint32_t insn, 22970b1347d2SRichard Henderson const DisasInsn *di) 22980b1347d2SRichard Henderson { 22990b1347d2SRichard Henderson unsigned rt = extract32(insn, 0, 5); 23000b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 23010b1347d2SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 23020b1347d2SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 23030b1347d2SRichard Henderson TCGv dest; 23040b1347d2SRichard Henderson 23050b1347d2SRichard Henderson if (c) { 23060b1347d2SRichard Henderson nullify_over(ctx); 23070b1347d2SRichard Henderson } 23080b1347d2SRichard Henderson 23090b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 23100b1347d2SRichard Henderson if (r1 == 0) { 23110b1347d2SRichard Henderson tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2)); 23120b1347d2SRichard Henderson tcg_gen_shr_tl(dest, dest, cpu_sar); 23130b1347d2SRichard Henderson } else if (r1 == r2) { 23140b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 23150b1347d2SRichard Henderson tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2)); 23160b1347d2SRichard Henderson tcg_gen_rotr_i32(t32, t32, cpu_sar); 23170b1347d2SRichard Henderson tcg_gen_extu_i32_tl(dest, t32); 23180b1347d2SRichard Henderson tcg_temp_free_i32(t32); 23190b1347d2SRichard Henderson } else { 23200b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 23210b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 23220b1347d2SRichard Henderson 23230b1347d2SRichard Henderson tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1)); 23240b1347d2SRichard Henderson tcg_gen_extu_tl_i64(s, cpu_sar); 23250b1347d2SRichard Henderson tcg_gen_shr_i64(t, t, s); 23260b1347d2SRichard Henderson tcg_gen_trunc_i64_tl(dest, t); 23270b1347d2SRichard Henderson 23280b1347d2SRichard Henderson tcg_temp_free_i64(t); 23290b1347d2SRichard Henderson tcg_temp_free_i64(s); 23300b1347d2SRichard Henderson } 23310b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 23320b1347d2SRichard Henderson 23330b1347d2SRichard Henderson /* Install the new nullification. */ 23340b1347d2SRichard Henderson cond_free(&ctx->null_cond); 23350b1347d2SRichard Henderson if (c) { 23360b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 23370b1347d2SRichard Henderson } 23380b1347d2SRichard Henderson return nullify_end(ctx, NO_EXIT); 23390b1347d2SRichard Henderson } 23400b1347d2SRichard Henderson 23410b1347d2SRichard Henderson static ExitStatus trans_shrpw_imm(DisasContext *ctx, uint32_t insn, 23420b1347d2SRichard Henderson const DisasInsn *di) 23430b1347d2SRichard Henderson { 23440b1347d2SRichard Henderson unsigned rt = extract32(insn, 0, 5); 23450b1347d2SRichard Henderson unsigned cpos = extract32(insn, 5, 5); 23460b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 23470b1347d2SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 23480b1347d2SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 23490b1347d2SRichard Henderson unsigned sa = 31 - cpos; 23500b1347d2SRichard Henderson TCGv dest, t2; 23510b1347d2SRichard Henderson 23520b1347d2SRichard Henderson if (c) { 23530b1347d2SRichard Henderson nullify_over(ctx); 23540b1347d2SRichard Henderson } 23550b1347d2SRichard Henderson 23560b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 23570b1347d2SRichard Henderson t2 = load_gpr(ctx, r2); 23580b1347d2SRichard Henderson if (r1 == r2) { 23590b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 23600b1347d2SRichard Henderson tcg_gen_trunc_tl_i32(t32, t2); 23610b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 23620b1347d2SRichard Henderson tcg_gen_extu_i32_tl(dest, t32); 23630b1347d2SRichard Henderson tcg_temp_free_i32(t32); 23640b1347d2SRichard Henderson } else if (r1 == 0) { 23650b1347d2SRichard Henderson tcg_gen_extract_tl(dest, t2, sa, 32 - sa); 23660b1347d2SRichard Henderson } else { 23670b1347d2SRichard Henderson TCGv t0 = tcg_temp_new(); 23680b1347d2SRichard Henderson tcg_gen_extract_tl(t0, t2, sa, 32 - sa); 23690b1347d2SRichard Henderson tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa); 23700b1347d2SRichard Henderson tcg_temp_free(t0); 23710b1347d2SRichard Henderson } 23720b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 23730b1347d2SRichard Henderson 23740b1347d2SRichard Henderson /* Install the new nullification. */ 23750b1347d2SRichard Henderson cond_free(&ctx->null_cond); 23760b1347d2SRichard Henderson if (c) { 23770b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 23780b1347d2SRichard Henderson } 23790b1347d2SRichard Henderson return nullify_end(ctx, NO_EXIT); 23800b1347d2SRichard Henderson } 23810b1347d2SRichard Henderson 23820b1347d2SRichard Henderson static ExitStatus trans_extrw_sar(DisasContext *ctx, uint32_t insn, 23830b1347d2SRichard Henderson const DisasInsn *di) 23840b1347d2SRichard Henderson { 23850b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 23860b1347d2SRichard Henderson unsigned is_se = extract32(insn, 10, 1); 23870b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 23880b1347d2SRichard Henderson unsigned rt = extract32(insn, 16, 5); 23890b1347d2SRichard Henderson unsigned rr = extract32(insn, 21, 5); 23900b1347d2SRichard Henderson unsigned len = 32 - clen; 23910b1347d2SRichard Henderson TCGv dest, src, tmp; 23920b1347d2SRichard Henderson 23930b1347d2SRichard Henderson if (c) { 23940b1347d2SRichard Henderson nullify_over(ctx); 23950b1347d2SRichard Henderson } 23960b1347d2SRichard Henderson 23970b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 23980b1347d2SRichard Henderson src = load_gpr(ctx, rr); 23990b1347d2SRichard Henderson tmp = tcg_temp_new(); 24000b1347d2SRichard Henderson 24010b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 24020b1347d2SRichard Henderson tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1); 24030b1347d2SRichard Henderson if (is_se) { 24040b1347d2SRichard Henderson tcg_gen_sar_tl(dest, src, tmp); 24050b1347d2SRichard Henderson tcg_gen_sextract_tl(dest, dest, 0, len); 24060b1347d2SRichard Henderson } else { 24070b1347d2SRichard Henderson tcg_gen_shr_tl(dest, src, tmp); 24080b1347d2SRichard Henderson tcg_gen_extract_tl(dest, dest, 0, len); 24090b1347d2SRichard Henderson } 24100b1347d2SRichard Henderson tcg_temp_free(tmp); 24110b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 24120b1347d2SRichard Henderson 24130b1347d2SRichard Henderson /* Install the new nullification. */ 24140b1347d2SRichard Henderson cond_free(&ctx->null_cond); 24150b1347d2SRichard Henderson if (c) { 24160b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 24170b1347d2SRichard Henderson } 24180b1347d2SRichard Henderson return nullify_end(ctx, NO_EXIT); 24190b1347d2SRichard Henderson } 24200b1347d2SRichard Henderson 24210b1347d2SRichard Henderson static ExitStatus trans_extrw_imm(DisasContext *ctx, uint32_t insn, 24220b1347d2SRichard Henderson const DisasInsn *di) 24230b1347d2SRichard Henderson { 24240b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 24250b1347d2SRichard Henderson unsigned pos = extract32(insn, 5, 5); 24260b1347d2SRichard Henderson unsigned is_se = extract32(insn, 10, 1); 24270b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 24280b1347d2SRichard Henderson unsigned rt = extract32(insn, 16, 5); 24290b1347d2SRichard Henderson unsigned rr = extract32(insn, 21, 5); 24300b1347d2SRichard Henderson unsigned len = 32 - clen; 24310b1347d2SRichard Henderson unsigned cpos = 31 - pos; 24320b1347d2SRichard Henderson TCGv dest, src; 24330b1347d2SRichard Henderson 24340b1347d2SRichard Henderson if (c) { 24350b1347d2SRichard Henderson nullify_over(ctx); 24360b1347d2SRichard Henderson } 24370b1347d2SRichard Henderson 24380b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 24390b1347d2SRichard Henderson src = load_gpr(ctx, rr); 24400b1347d2SRichard Henderson if (is_se) { 24410b1347d2SRichard Henderson tcg_gen_sextract_tl(dest, src, cpos, len); 24420b1347d2SRichard Henderson } else { 24430b1347d2SRichard Henderson tcg_gen_extract_tl(dest, src, cpos, len); 24440b1347d2SRichard Henderson } 24450b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 24460b1347d2SRichard Henderson 24470b1347d2SRichard Henderson /* Install the new nullification. */ 24480b1347d2SRichard Henderson cond_free(&ctx->null_cond); 24490b1347d2SRichard Henderson if (c) { 24500b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 24510b1347d2SRichard Henderson } 24520b1347d2SRichard Henderson return nullify_end(ctx, NO_EXIT); 24530b1347d2SRichard Henderson } 24540b1347d2SRichard Henderson 24550b1347d2SRichard Henderson static const DisasInsn table_sh_ex[] = { 24560b1347d2SRichard Henderson { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar }, 24570b1347d2SRichard Henderson { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm }, 24580b1347d2SRichard Henderson { 0xd0001000u, 0xfc001be0u, trans_extrw_sar }, 24590b1347d2SRichard Henderson { 0xd0001800u, 0xfc001800u, trans_extrw_imm }, 24600b1347d2SRichard Henderson }; 24610b1347d2SRichard Henderson 24620b1347d2SRichard Henderson static ExitStatus trans_depw_imm_c(DisasContext *ctx, uint32_t insn, 24630b1347d2SRichard Henderson const DisasInsn *di) 24640b1347d2SRichard Henderson { 24650b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 24660b1347d2SRichard Henderson unsigned cpos = extract32(insn, 5, 5); 24670b1347d2SRichard Henderson unsigned nz = extract32(insn, 10, 1); 24680b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 24690b1347d2SRichard Henderson target_long val = low_sextract(insn, 16, 5); 24700b1347d2SRichard Henderson unsigned rt = extract32(insn, 21, 5); 24710b1347d2SRichard Henderson unsigned len = 32 - clen; 24720b1347d2SRichard Henderson target_long mask0, mask1; 24730b1347d2SRichard Henderson TCGv dest; 24740b1347d2SRichard Henderson 24750b1347d2SRichard Henderson if (c) { 24760b1347d2SRichard Henderson nullify_over(ctx); 24770b1347d2SRichard Henderson } 24780b1347d2SRichard Henderson if (cpos + len > 32) { 24790b1347d2SRichard Henderson len = 32 - cpos; 24800b1347d2SRichard Henderson } 24810b1347d2SRichard Henderson 24820b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 24830b1347d2SRichard Henderson mask0 = deposit64(0, cpos, len, val); 24840b1347d2SRichard Henderson mask1 = deposit64(-1, cpos, len, val); 24850b1347d2SRichard Henderson 24860b1347d2SRichard Henderson if (nz) { 24870b1347d2SRichard Henderson TCGv src = load_gpr(ctx, rt); 24880b1347d2SRichard Henderson if (mask1 != -1) { 24890b1347d2SRichard Henderson tcg_gen_andi_tl(dest, src, mask1); 24900b1347d2SRichard Henderson src = dest; 24910b1347d2SRichard Henderson } 24920b1347d2SRichard Henderson tcg_gen_ori_tl(dest, src, mask0); 24930b1347d2SRichard Henderson } else { 24940b1347d2SRichard Henderson tcg_gen_movi_tl(dest, mask0); 24950b1347d2SRichard Henderson } 24960b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 24970b1347d2SRichard Henderson 24980b1347d2SRichard Henderson /* Install the new nullification. */ 24990b1347d2SRichard Henderson cond_free(&ctx->null_cond); 25000b1347d2SRichard Henderson if (c) { 25010b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 25020b1347d2SRichard Henderson } 25030b1347d2SRichard Henderson return nullify_end(ctx, NO_EXIT); 25040b1347d2SRichard Henderson } 25050b1347d2SRichard Henderson 25060b1347d2SRichard Henderson static ExitStatus trans_depw_imm(DisasContext *ctx, uint32_t insn, 25070b1347d2SRichard Henderson const DisasInsn *di) 25080b1347d2SRichard Henderson { 25090b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 25100b1347d2SRichard Henderson unsigned cpos = extract32(insn, 5, 5); 25110b1347d2SRichard Henderson unsigned nz = extract32(insn, 10, 1); 25120b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 25130b1347d2SRichard Henderson unsigned rr = extract32(insn, 16, 5); 25140b1347d2SRichard Henderson unsigned rt = extract32(insn, 21, 5); 25150b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 25160b1347d2SRichard Henderson unsigned len = 32 - clen; 25170b1347d2SRichard Henderson TCGv dest, val; 25180b1347d2SRichard Henderson 25190b1347d2SRichard Henderson if (c) { 25200b1347d2SRichard Henderson nullify_over(ctx); 25210b1347d2SRichard Henderson } 25220b1347d2SRichard Henderson if (cpos + len > 32) { 25230b1347d2SRichard Henderson len = 32 - cpos; 25240b1347d2SRichard Henderson } 25250b1347d2SRichard Henderson 25260b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 25270b1347d2SRichard Henderson val = load_gpr(ctx, rr); 25280b1347d2SRichard Henderson if (rs == 0) { 25290b1347d2SRichard Henderson tcg_gen_deposit_z_tl(dest, val, cpos, len); 25300b1347d2SRichard Henderson } else { 25310b1347d2SRichard Henderson tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len); 25320b1347d2SRichard Henderson } 25330b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 25340b1347d2SRichard Henderson 25350b1347d2SRichard Henderson /* Install the new nullification. */ 25360b1347d2SRichard Henderson cond_free(&ctx->null_cond); 25370b1347d2SRichard Henderson if (c) { 25380b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 25390b1347d2SRichard Henderson } 25400b1347d2SRichard Henderson return nullify_end(ctx, NO_EXIT); 25410b1347d2SRichard Henderson } 25420b1347d2SRichard Henderson 25430b1347d2SRichard Henderson static ExitStatus trans_depw_sar(DisasContext *ctx, uint32_t insn, 25440b1347d2SRichard Henderson const DisasInsn *di) 25450b1347d2SRichard Henderson { 25460b1347d2SRichard Henderson unsigned clen = extract32(insn, 0, 5); 25470b1347d2SRichard Henderson unsigned nz = extract32(insn, 10, 1); 25480b1347d2SRichard Henderson unsigned i = extract32(insn, 12, 1); 25490b1347d2SRichard Henderson unsigned c = extract32(insn, 13, 3); 25500b1347d2SRichard Henderson unsigned rt = extract32(insn, 21, 5); 25510b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 25520b1347d2SRichard Henderson unsigned len = 32 - clen; 25530b1347d2SRichard Henderson TCGv val, mask, tmp, shift, dest; 25540b1347d2SRichard Henderson unsigned msb = 1U << (len - 1); 25550b1347d2SRichard Henderson 25560b1347d2SRichard Henderson if (c) { 25570b1347d2SRichard Henderson nullify_over(ctx); 25580b1347d2SRichard Henderson } 25590b1347d2SRichard Henderson 25600b1347d2SRichard Henderson if (i) { 25610b1347d2SRichard Henderson val = load_const(ctx, low_sextract(insn, 16, 5)); 25620b1347d2SRichard Henderson } else { 25630b1347d2SRichard Henderson val = load_gpr(ctx, extract32(insn, 16, 5)); 25640b1347d2SRichard Henderson } 25650b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 25660b1347d2SRichard Henderson shift = tcg_temp_new(); 25670b1347d2SRichard Henderson tmp = tcg_temp_new(); 25680b1347d2SRichard Henderson 25690b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 25700b1347d2SRichard Henderson tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1); 25710b1347d2SRichard Henderson 25720b1347d2SRichard Henderson mask = tcg_const_tl(msb + (msb - 1)); 25730b1347d2SRichard Henderson tcg_gen_and_tl(tmp, val, mask); 25740b1347d2SRichard Henderson if (rs) { 25750b1347d2SRichard Henderson tcg_gen_shl_tl(mask, mask, shift); 25760b1347d2SRichard Henderson tcg_gen_shl_tl(tmp, tmp, shift); 25770b1347d2SRichard Henderson tcg_gen_andc_tl(dest, cpu_gr[rs], mask); 25780b1347d2SRichard Henderson tcg_gen_or_tl(dest, dest, tmp); 25790b1347d2SRichard Henderson } else { 25800b1347d2SRichard Henderson tcg_gen_shl_tl(dest, tmp, shift); 25810b1347d2SRichard Henderson } 25820b1347d2SRichard Henderson tcg_temp_free(shift); 25830b1347d2SRichard Henderson tcg_temp_free(mask); 25840b1347d2SRichard Henderson tcg_temp_free(tmp); 25850b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 25860b1347d2SRichard Henderson 25870b1347d2SRichard Henderson /* Install the new nullification. */ 25880b1347d2SRichard Henderson cond_free(&ctx->null_cond); 25890b1347d2SRichard Henderson if (c) { 25900b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 25910b1347d2SRichard Henderson } 25920b1347d2SRichard Henderson return nullify_end(ctx, NO_EXIT); 25930b1347d2SRichard Henderson } 25940b1347d2SRichard Henderson 25950b1347d2SRichard Henderson static const DisasInsn table_depw[] = { 25960b1347d2SRichard Henderson { 0xd4000000u, 0xfc000be0u, trans_depw_sar }, 25970b1347d2SRichard Henderson { 0xd4000800u, 0xfc001800u, trans_depw_imm }, 25980b1347d2SRichard Henderson { 0xd4001800u, 0xfc001800u, trans_depw_imm_c }, 25990b1347d2SRichard Henderson }; 26000b1347d2SRichard Henderson 260198cd9ca7SRichard Henderson static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l) 260298cd9ca7SRichard Henderson { 260398cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 260498cd9ca7SRichard Henderson unsigned b = extract32(insn, 21, 5); 260598cd9ca7SRichard Henderson target_long disp = assemble_17(insn); 260698cd9ca7SRichard Henderson 260798cd9ca7SRichard Henderson /* unsigned s = low_uextract(insn, 13, 3); */ 260898cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 260998cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 261098cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 261198cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 261298cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 261398cd9ca7SRichard Henderson 261498cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 261598cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 261698cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 261798cd9ca7SRichard Henderson if (b == 0) { 261898cd9ca7SRichard Henderson return do_dbranch(ctx, disp, is_l ? 31 : 0, n); 261998cd9ca7SRichard Henderson } else { 262098cd9ca7SRichard Henderson TCGv tmp = get_temp(ctx); 262198cd9ca7SRichard Henderson tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp); 262298cd9ca7SRichard Henderson return do_ibranch(ctx, tmp, is_l ? 31 : 0, n); 262398cd9ca7SRichard Henderson } 262498cd9ca7SRichard Henderson } 262598cd9ca7SRichard Henderson 262698cd9ca7SRichard Henderson static ExitStatus trans_bl(DisasContext *ctx, uint32_t insn, 262798cd9ca7SRichard Henderson const DisasInsn *di) 262898cd9ca7SRichard Henderson { 262998cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 263098cd9ca7SRichard Henderson unsigned link = extract32(insn, 21, 5); 263198cd9ca7SRichard Henderson target_long disp = assemble_17(insn); 263298cd9ca7SRichard Henderson 263398cd9ca7SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n); 263498cd9ca7SRichard Henderson } 263598cd9ca7SRichard Henderson 263698cd9ca7SRichard Henderson static ExitStatus trans_bl_long(DisasContext *ctx, uint32_t insn, 263798cd9ca7SRichard Henderson const DisasInsn *di) 263898cd9ca7SRichard Henderson { 263998cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 264098cd9ca7SRichard Henderson target_long disp = assemble_22(insn); 264198cd9ca7SRichard Henderson 264298cd9ca7SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n); 264398cd9ca7SRichard Henderson } 264498cd9ca7SRichard Henderson 264598cd9ca7SRichard Henderson static ExitStatus trans_blr(DisasContext *ctx, uint32_t insn, 264698cd9ca7SRichard Henderson const DisasInsn *di) 264798cd9ca7SRichard Henderson { 264898cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 264998cd9ca7SRichard Henderson unsigned rx = extract32(insn, 16, 5); 265098cd9ca7SRichard Henderson unsigned link = extract32(insn, 21, 5); 265198cd9ca7SRichard Henderson TCGv tmp = get_temp(ctx); 265298cd9ca7SRichard Henderson 265398cd9ca7SRichard Henderson tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3); 265498cd9ca7SRichard Henderson tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8); 265598cd9ca7SRichard Henderson return do_ibranch(ctx, tmp, link, n); 265698cd9ca7SRichard Henderson } 265798cd9ca7SRichard Henderson 265898cd9ca7SRichard Henderson static ExitStatus trans_bv(DisasContext *ctx, uint32_t insn, 265998cd9ca7SRichard Henderson const DisasInsn *di) 266098cd9ca7SRichard Henderson { 266198cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 266298cd9ca7SRichard Henderson unsigned rx = extract32(insn, 16, 5); 266398cd9ca7SRichard Henderson unsigned rb = extract32(insn, 21, 5); 266498cd9ca7SRichard Henderson TCGv dest; 266598cd9ca7SRichard Henderson 266698cd9ca7SRichard Henderson if (rx == 0) { 266798cd9ca7SRichard Henderson dest = load_gpr(ctx, rb); 266898cd9ca7SRichard Henderson } else { 266998cd9ca7SRichard Henderson dest = get_temp(ctx); 267098cd9ca7SRichard Henderson tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3); 267198cd9ca7SRichard Henderson tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb)); 267298cd9ca7SRichard Henderson } 267398cd9ca7SRichard Henderson return do_ibranch(ctx, dest, 0, n); 267498cd9ca7SRichard Henderson } 267598cd9ca7SRichard Henderson 267698cd9ca7SRichard Henderson static ExitStatus trans_bve(DisasContext *ctx, uint32_t insn, 267798cd9ca7SRichard Henderson const DisasInsn *di) 267898cd9ca7SRichard Henderson { 267998cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 268098cd9ca7SRichard Henderson unsigned rb = extract32(insn, 21, 5); 268198cd9ca7SRichard Henderson unsigned link = extract32(insn, 13, 1) ? 2 : 0; 268298cd9ca7SRichard Henderson 268398cd9ca7SRichard Henderson return do_ibranch(ctx, load_gpr(ctx, rb), link, n); 268498cd9ca7SRichard Henderson } 268598cd9ca7SRichard Henderson 268698cd9ca7SRichard Henderson static const DisasInsn table_branch[] = { 268798cd9ca7SRichard Henderson { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */ 268898cd9ca7SRichard Henderson { 0xe800a000u, 0xfc00e000u, trans_bl_long }, 268998cd9ca7SRichard Henderson { 0xe8004000u, 0xfc00fffdu, trans_blr }, 269098cd9ca7SRichard Henderson { 0xe800c000u, 0xfc00fffdu, trans_bv }, 269198cd9ca7SRichard Henderson { 0xe800d000u, 0xfc00dffcu, trans_bve }, 269298cd9ca7SRichard Henderson }; 269398cd9ca7SRichard Henderson 269461766fe9SRichard Henderson static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn, 269561766fe9SRichard Henderson const DisasInsn table[], size_t n) 269661766fe9SRichard Henderson { 269761766fe9SRichard Henderson size_t i; 269861766fe9SRichard Henderson for (i = 0; i < n; ++i) { 269961766fe9SRichard Henderson if ((insn & table[i].mask) == table[i].insn) { 270061766fe9SRichard Henderson return table[i].trans(ctx, insn, &table[i]); 270161766fe9SRichard Henderson } 270261766fe9SRichard Henderson } 270361766fe9SRichard Henderson return gen_illegal(ctx); 270461766fe9SRichard Henderson } 270561766fe9SRichard Henderson 270661766fe9SRichard Henderson #define translate_table(ctx, insn, table) \ 270761766fe9SRichard Henderson translate_table_int(ctx, insn, table, ARRAY_SIZE(table)) 270861766fe9SRichard Henderson 270961766fe9SRichard Henderson static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) 271061766fe9SRichard Henderson { 271161766fe9SRichard Henderson uint32_t opc = extract32(insn, 26, 6); 271261766fe9SRichard Henderson 271361766fe9SRichard Henderson switch (opc) { 2714b2167459SRichard Henderson case 0x02: 2715b2167459SRichard Henderson return translate_table(ctx, insn, table_arith_log); 2716*96d6407fSRichard Henderson case 0x03: 2717*96d6407fSRichard Henderson return translate_table(ctx, insn, table_index_mem); 2718b2167459SRichard Henderson case 0x08: 2719b2167459SRichard Henderson return trans_ldil(ctx, insn); 2720*96d6407fSRichard Henderson case 0x09: 2721*96d6407fSRichard Henderson return trans_copr_w(ctx, insn); 2722b2167459SRichard Henderson case 0x0A: 2723b2167459SRichard Henderson return trans_addil(ctx, insn); 2724*96d6407fSRichard Henderson case 0x0B: 2725*96d6407fSRichard Henderson return trans_copr_dw(ctx, insn); 2726b2167459SRichard Henderson case 0x0D: 2727b2167459SRichard Henderson return trans_ldo(ctx, insn); 2728*96d6407fSRichard Henderson 2729*96d6407fSRichard Henderson case 0x10: 2730*96d6407fSRichard Henderson return trans_load(ctx, insn, false, MO_UB); 2731*96d6407fSRichard Henderson case 0x11: 2732*96d6407fSRichard Henderson return trans_load(ctx, insn, false, MO_TEUW); 2733*96d6407fSRichard Henderson case 0x12: 2734*96d6407fSRichard Henderson return trans_load(ctx, insn, false, MO_TEUL); 2735*96d6407fSRichard Henderson case 0x13: 2736*96d6407fSRichard Henderson return trans_load(ctx, insn, true, MO_TEUL); 2737*96d6407fSRichard Henderson case 0x16: 2738*96d6407fSRichard Henderson return trans_fload_mod(ctx, insn); 2739*96d6407fSRichard Henderson case 0x17: 2740*96d6407fSRichard Henderson return trans_load_w(ctx, insn); 2741*96d6407fSRichard Henderson case 0x18: 2742*96d6407fSRichard Henderson return trans_store(ctx, insn, false, MO_UB); 2743*96d6407fSRichard Henderson case 0x19: 2744*96d6407fSRichard Henderson return trans_store(ctx, insn, false, MO_TEUW); 2745*96d6407fSRichard Henderson case 0x1A: 2746*96d6407fSRichard Henderson return trans_store(ctx, insn, false, MO_TEUL); 2747*96d6407fSRichard Henderson case 0x1B: 2748*96d6407fSRichard Henderson return trans_store(ctx, insn, true, MO_TEUL); 2749*96d6407fSRichard Henderson case 0x1E: 2750*96d6407fSRichard Henderson return trans_fstore_mod(ctx, insn); 2751*96d6407fSRichard Henderson case 0x1F: 2752*96d6407fSRichard Henderson return trans_store_w(ctx, insn); 2753*96d6407fSRichard Henderson 275498cd9ca7SRichard Henderson case 0x20: 275598cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, false, false); 275698cd9ca7SRichard Henderson case 0x21: 275798cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, true, false); 275898cd9ca7SRichard Henderson case 0x22: 275998cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, false, false); 276098cd9ca7SRichard Henderson case 0x23: 276198cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, true, false); 2762b2167459SRichard Henderson case 0x24: 2763b2167459SRichard Henderson return trans_cmpiclr(ctx, insn); 2764b2167459SRichard Henderson case 0x25: 2765b2167459SRichard Henderson return trans_subi(ctx, insn); 276698cd9ca7SRichard Henderson case 0x27: 276798cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, false, true); 276898cd9ca7SRichard Henderson case 0x28: 276998cd9ca7SRichard Henderson return trans_addb(ctx, insn, true, false); 277098cd9ca7SRichard Henderson case 0x29: 277198cd9ca7SRichard Henderson return trans_addb(ctx, insn, true, true); 277298cd9ca7SRichard Henderson case 0x2A: 277398cd9ca7SRichard Henderson return trans_addb(ctx, insn, false, false); 277498cd9ca7SRichard Henderson case 0x2B: 277598cd9ca7SRichard Henderson return trans_addb(ctx, insn, false, true); 2776b2167459SRichard Henderson case 0x2C: 2777b2167459SRichard Henderson case 0x2D: 2778b2167459SRichard Henderson return trans_addi(ctx, insn); 277998cd9ca7SRichard Henderson case 0x2F: 278098cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, false, true); 2781*96d6407fSRichard Henderson 278298cd9ca7SRichard Henderson case 0x30: 278398cd9ca7SRichard Henderson case 0x31: 278498cd9ca7SRichard Henderson return trans_bb(ctx, insn); 278598cd9ca7SRichard Henderson case 0x32: 278698cd9ca7SRichard Henderson return trans_movb(ctx, insn, false); 278798cd9ca7SRichard Henderson case 0x33: 278898cd9ca7SRichard Henderson return trans_movb(ctx, insn, true); 27890b1347d2SRichard Henderson case 0x34: 27900b1347d2SRichard Henderson return translate_table(ctx, insn, table_sh_ex); 27910b1347d2SRichard Henderson case 0x35: 27920b1347d2SRichard Henderson return translate_table(ctx, insn, table_depw); 279398cd9ca7SRichard Henderson case 0x38: 279498cd9ca7SRichard Henderson return trans_be(ctx, insn, false); 279598cd9ca7SRichard Henderson case 0x39: 279698cd9ca7SRichard Henderson return trans_be(ctx, insn, true); 279798cd9ca7SRichard Henderson case 0x3A: 279898cd9ca7SRichard Henderson return translate_table(ctx, insn, table_branch); 2799*96d6407fSRichard Henderson 2800*96d6407fSRichard Henderson case 0x04: /* spopn */ 2801*96d6407fSRichard Henderson case 0x05: /* diag */ 2802*96d6407fSRichard Henderson case 0x0F: /* product specific */ 2803*96d6407fSRichard Henderson break; 2804*96d6407fSRichard Henderson 2805*96d6407fSRichard Henderson case 0x07: /* unassigned */ 2806*96d6407fSRichard Henderson case 0x15: /* unassigned */ 2807*96d6407fSRichard Henderson case 0x1D: /* unassigned */ 2808*96d6407fSRichard Henderson case 0x37: /* unassigned */ 2809*96d6407fSRichard Henderson case 0x3F: /* unassigned */ 281061766fe9SRichard Henderson default: 281161766fe9SRichard Henderson break; 281261766fe9SRichard Henderson } 281361766fe9SRichard Henderson return gen_illegal(ctx); 281461766fe9SRichard Henderson } 281561766fe9SRichard Henderson 281661766fe9SRichard Henderson void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb) 281761766fe9SRichard Henderson { 281861766fe9SRichard Henderson HPPACPU *cpu = hppa_env_get_cpu(env); 281961766fe9SRichard Henderson CPUState *cs = CPU(cpu); 282061766fe9SRichard Henderson DisasContext ctx; 282161766fe9SRichard Henderson ExitStatus ret; 282261766fe9SRichard Henderson int num_insns, max_insns, i; 282361766fe9SRichard Henderson 282461766fe9SRichard Henderson ctx.tb = tb; 282561766fe9SRichard Henderson ctx.cs = cs; 282661766fe9SRichard Henderson ctx.iaoq_f = tb->pc; 282761766fe9SRichard Henderson ctx.iaoq_b = tb->cs_base; 282861766fe9SRichard Henderson ctx.singlestep_enabled = cs->singlestep_enabled; 282961766fe9SRichard Henderson 283061766fe9SRichard Henderson ctx.ntemps = 0; 283161766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) { 283261766fe9SRichard Henderson TCGV_UNUSED(ctx.temps[i]); 283361766fe9SRichard Henderson } 283461766fe9SRichard Henderson 283561766fe9SRichard Henderson /* Compute the maximum number of insns to execute, as bounded by 283661766fe9SRichard Henderson (1) icount, (2) single-stepping, (3) branch delay slots, or 283761766fe9SRichard Henderson (4) the number of insns remaining on the current page. */ 283861766fe9SRichard Henderson max_insns = tb->cflags & CF_COUNT_MASK; 283961766fe9SRichard Henderson if (max_insns == 0) { 284061766fe9SRichard Henderson max_insns = CF_COUNT_MASK; 284161766fe9SRichard Henderson } 284261766fe9SRichard Henderson if (ctx.singlestep_enabled || singlestep) { 284361766fe9SRichard Henderson max_insns = 1; 284461766fe9SRichard Henderson } else if (max_insns > TCG_MAX_INSNS) { 284561766fe9SRichard Henderson max_insns = TCG_MAX_INSNS; 284661766fe9SRichard Henderson } 284761766fe9SRichard Henderson 284861766fe9SRichard Henderson num_insns = 0; 284961766fe9SRichard Henderson gen_tb_start(tb); 285061766fe9SRichard Henderson 2851129e9cc3SRichard Henderson /* Seed the nullification status from PSW[N], as shown in TB->FLAGS. */ 2852129e9cc3SRichard Henderson ctx.null_cond = cond_make_f(); 2853129e9cc3SRichard Henderson ctx.psw_n_nonzero = false; 2854129e9cc3SRichard Henderson if (tb->flags & 1) { 2855129e9cc3SRichard Henderson ctx.null_cond.c = TCG_COND_ALWAYS; 2856129e9cc3SRichard Henderson ctx.psw_n_nonzero = true; 2857129e9cc3SRichard Henderson } 2858129e9cc3SRichard Henderson ctx.null_lab = NULL; 2859129e9cc3SRichard Henderson 286061766fe9SRichard Henderson do { 286161766fe9SRichard Henderson tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b); 286261766fe9SRichard Henderson num_insns++; 286361766fe9SRichard Henderson 286461766fe9SRichard Henderson if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) { 286561766fe9SRichard Henderson ret = gen_excp(&ctx, EXCP_DEBUG); 286661766fe9SRichard Henderson break; 286761766fe9SRichard Henderson } 286861766fe9SRichard Henderson if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { 286961766fe9SRichard Henderson gen_io_start(); 287061766fe9SRichard Henderson } 287161766fe9SRichard Henderson 28727ad439dfSRichard Henderson if (ctx.iaoq_f < TARGET_PAGE_SIZE) { 28737ad439dfSRichard Henderson ret = do_page_zero(&ctx); 28747ad439dfSRichard Henderson assert(ret != NO_EXIT); 28757ad439dfSRichard Henderson } else { 287661766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 287761766fe9SRichard Henderson the page permissions for execute. */ 287861766fe9SRichard Henderson uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f); 287961766fe9SRichard Henderson 288061766fe9SRichard Henderson /* Set up the IA queue for the next insn. 288161766fe9SRichard Henderson This will be overwritten by a branch. */ 288261766fe9SRichard Henderson if (ctx.iaoq_b == -1) { 288361766fe9SRichard Henderson ctx.iaoq_n = -1; 288461766fe9SRichard Henderson ctx.iaoq_n_var = get_temp(&ctx); 288561766fe9SRichard Henderson tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4); 288661766fe9SRichard Henderson } else { 288761766fe9SRichard Henderson ctx.iaoq_n = ctx.iaoq_b + 4; 288861766fe9SRichard Henderson TCGV_UNUSED(ctx.iaoq_n_var); 288961766fe9SRichard Henderson } 289061766fe9SRichard Henderson 2891129e9cc3SRichard Henderson if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) { 2892129e9cc3SRichard Henderson ctx.null_cond.c = TCG_COND_NEVER; 2893129e9cc3SRichard Henderson ret = NO_EXIT; 2894129e9cc3SRichard Henderson } else { 289561766fe9SRichard Henderson ret = translate_one(&ctx, insn); 2896129e9cc3SRichard Henderson assert(ctx.null_lab == NULL); 2897129e9cc3SRichard Henderson } 289861766fe9SRichard Henderson } 289961766fe9SRichard Henderson 290061766fe9SRichard Henderson for (i = 0; i < ctx.ntemps; ++i) { 290161766fe9SRichard Henderson tcg_temp_free(ctx.temps[i]); 290261766fe9SRichard Henderson TCGV_UNUSED(ctx.temps[i]); 290361766fe9SRichard Henderson } 290461766fe9SRichard Henderson ctx.ntemps = 0; 290561766fe9SRichard Henderson 290661766fe9SRichard Henderson /* If we see non-linear instructions, exhaust instruction count, 290761766fe9SRichard Henderson or run out of buffer space, stop generation. */ 290861766fe9SRichard Henderson /* ??? The non-linear instruction restriction is purely due to 290961766fe9SRichard Henderson the debugging dump. Otherwise we *could* follow unconditional 291061766fe9SRichard Henderson branches within the same page. */ 291161766fe9SRichard Henderson if (ret == NO_EXIT 291261766fe9SRichard Henderson && (ctx.iaoq_b != ctx.iaoq_f + 4 291361766fe9SRichard Henderson || num_insns >= max_insns 291461766fe9SRichard Henderson || tcg_op_buf_full())) { 2915129e9cc3SRichard Henderson if (ctx.null_cond.c == TCG_COND_NEVER 2916129e9cc3SRichard Henderson || ctx.null_cond.c == TCG_COND_ALWAYS) { 2917129e9cc3SRichard Henderson nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS); 2918129e9cc3SRichard Henderson gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n); 2919129e9cc3SRichard Henderson ret = EXIT_GOTO_TB; 2920129e9cc3SRichard Henderson } else { 292161766fe9SRichard Henderson ret = EXIT_IAQ_N_STALE; 292261766fe9SRichard Henderson } 2923129e9cc3SRichard Henderson } 292461766fe9SRichard Henderson 292561766fe9SRichard Henderson ctx.iaoq_f = ctx.iaoq_b; 292661766fe9SRichard Henderson ctx.iaoq_b = ctx.iaoq_n; 292761766fe9SRichard Henderson if (ret == EXIT_NORETURN 292861766fe9SRichard Henderson || ret == EXIT_GOTO_TB 292961766fe9SRichard Henderson || ret == EXIT_IAQ_N_UPDATED) { 293061766fe9SRichard Henderson break; 293161766fe9SRichard Henderson } 293261766fe9SRichard Henderson if (ctx.iaoq_f == -1) { 293361766fe9SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b); 293461766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var); 2935129e9cc3SRichard Henderson nullify_save(&ctx); 293661766fe9SRichard Henderson ret = EXIT_IAQ_N_UPDATED; 293761766fe9SRichard Henderson break; 293861766fe9SRichard Henderson } 293961766fe9SRichard Henderson if (ctx.iaoq_b == -1) { 294061766fe9SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var); 294161766fe9SRichard Henderson } 294261766fe9SRichard Henderson } while (ret == NO_EXIT); 294361766fe9SRichard Henderson 294461766fe9SRichard Henderson if (tb->cflags & CF_LAST_IO) { 294561766fe9SRichard Henderson gen_io_end(); 294661766fe9SRichard Henderson } 294761766fe9SRichard Henderson 294861766fe9SRichard Henderson switch (ret) { 294961766fe9SRichard Henderson case EXIT_GOTO_TB: 295061766fe9SRichard Henderson case EXIT_NORETURN: 295161766fe9SRichard Henderson break; 295261766fe9SRichard Henderson case EXIT_IAQ_N_STALE: 295361766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f); 295461766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b); 2955129e9cc3SRichard Henderson nullify_save(&ctx); 295661766fe9SRichard Henderson /* FALLTHRU */ 295761766fe9SRichard Henderson case EXIT_IAQ_N_UPDATED: 295861766fe9SRichard Henderson if (ctx.singlestep_enabled) { 295961766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 296061766fe9SRichard Henderson } else { 296161766fe9SRichard Henderson tcg_gen_exit_tb(0); 296261766fe9SRichard Henderson } 296361766fe9SRichard Henderson break; 296461766fe9SRichard Henderson default: 296561766fe9SRichard Henderson abort(); 296661766fe9SRichard Henderson } 296761766fe9SRichard Henderson 296861766fe9SRichard Henderson gen_tb_end(tb, num_insns); 296961766fe9SRichard Henderson 297061766fe9SRichard Henderson tb->size = num_insns * 4; 297161766fe9SRichard Henderson tb->icount = num_insns; 297261766fe9SRichard Henderson 297361766fe9SRichard Henderson #ifdef DEBUG_DISAS 297461766fe9SRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) 297561766fe9SRichard Henderson && qemu_log_in_addr_range(tb->pc)) { 297661766fe9SRichard Henderson qemu_log_lock(); 29777ad439dfSRichard Henderson switch (tb->pc) { 29787ad439dfSRichard Henderson case 0x00: 29797ad439dfSRichard Henderson qemu_log("IN:\n0x00000000: (null)\n\n"); 29807ad439dfSRichard Henderson break; 29817ad439dfSRichard Henderson case 0xb0: 29827ad439dfSRichard Henderson qemu_log("IN:\n0x000000b0: light-weight-syscall\n\n"); 29837ad439dfSRichard Henderson break; 29847ad439dfSRichard Henderson case 0xe0: 29857ad439dfSRichard Henderson qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n\n"); 29867ad439dfSRichard Henderson break; 29877ad439dfSRichard Henderson case 0x100: 29887ad439dfSRichard Henderson qemu_log("IN:\n0x00000100: syscall\n\n"); 29897ad439dfSRichard Henderson break; 29907ad439dfSRichard Henderson default: 299161766fe9SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(tb->pc)); 299261766fe9SRichard Henderson log_target_disas(cs, tb->pc, tb->size, 1); 299361766fe9SRichard Henderson qemu_log("\n"); 29947ad439dfSRichard Henderson break; 29957ad439dfSRichard Henderson } 299661766fe9SRichard Henderson qemu_log_unlock(); 299761766fe9SRichard Henderson } 299861766fe9SRichard Henderson #endif 299961766fe9SRichard Henderson } 300061766fe9SRichard Henderson 300161766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb, 300261766fe9SRichard Henderson target_ulong *data) 300361766fe9SRichard Henderson { 300461766fe9SRichard Henderson env->iaoq_f = data[0]; 300561766fe9SRichard Henderson if (data[1] != -1) { 300661766fe9SRichard Henderson env->iaoq_b = data[1]; 300761766fe9SRichard Henderson } 300861766fe9SRichard Henderson /* Since we were executing the instruction at IAOQ_F, and took some 300961766fe9SRichard Henderson sort of action that provoked the cpu_restore_state, we can infer 301061766fe9SRichard Henderson that the instruction was not nullified. */ 301161766fe9SRichard Henderson env->psw_n = 0; 301261766fe9SRichard Henderson } 3013