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 281129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 282129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 283129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 284129e9cc3SRichard Henderson { 285129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 286129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 287129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 288129e9cc3SRichard Henderson 289129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 290129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 291129e9cc3SRichard Henderson 292129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 293129e9cc3SRichard Henderson if (ctx->null_cond.a0_is_n) { 294129e9cc3SRichard Henderson ctx->null_cond.a0_is_n = false; 295129e9cc3SRichard Henderson ctx->null_cond.a0 = tcg_temp_new(); 296129e9cc3SRichard Henderson tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n); 297129e9cc3SRichard Henderson } 298129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 299129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 300129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 301129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 302129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 303129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, 0); 304129e9cc3SRichard Henderson } 305129e9cc3SRichard Henderson 306129e9cc3SRichard Henderson tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0, 307129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 308129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 309129e9cc3SRichard Henderson } 310129e9cc3SRichard Henderson } 311129e9cc3SRichard Henderson 312129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 313129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 314129e9cc3SRichard Henderson { 315129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 316129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 317129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, 0); 318129e9cc3SRichard Henderson } 319129e9cc3SRichard Henderson return; 320129e9cc3SRichard Henderson } 321129e9cc3SRichard Henderson if (!ctx->null_cond.a0_is_n) { 322129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 323129e9cc3SRichard Henderson tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n, 324129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 325129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 326129e9cc3SRichard Henderson } 327129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 328129e9cc3SRichard Henderson } 329129e9cc3SRichard Henderson 330129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 331129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 332129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 333129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 334129e9cc3SRichard Henderson { 335129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 336129e9cc3SRichard Henderson tcg_gen_movi_tl(cpu_psw_n, x); 337129e9cc3SRichard Henderson } 338129e9cc3SRichard Henderson } 339129e9cc3SRichard Henderson 340129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 341129e9cc3SRichard Henderson This is the pair to nullify_over. */ 342129e9cc3SRichard Henderson static ExitStatus nullify_end(DisasContext *ctx, ExitStatus status) 343129e9cc3SRichard Henderson { 344129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 345129e9cc3SRichard Henderson 346129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 347129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 348129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 349129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 350129e9cc3SRichard Henderson return status; 351129e9cc3SRichard Henderson } 352129e9cc3SRichard Henderson ctx->null_lab = NULL; 353129e9cc3SRichard Henderson 354129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 355129e9cc3SRichard Henderson /* The next instruction will be unconditional, 356129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 357129e9cc3SRichard Henderson gen_set_label(null_lab); 358129e9cc3SRichard Henderson } else { 359129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 360129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 361129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 362129e9cc3SRichard Henderson label we have the proper value in place. */ 363129e9cc3SRichard Henderson nullify_save(ctx); 364129e9cc3SRichard Henderson gen_set_label(null_lab); 365129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 366129e9cc3SRichard Henderson } 367129e9cc3SRichard Henderson 368129e9cc3SRichard Henderson assert(status != EXIT_GOTO_TB && status != EXIT_IAQ_N_UPDATED); 369129e9cc3SRichard Henderson if (status == EXIT_NORETURN) { 370129e9cc3SRichard Henderson status = NO_EXIT; 371129e9cc3SRichard Henderson } 372129e9cc3SRichard Henderson return status; 373129e9cc3SRichard Henderson } 374129e9cc3SRichard Henderson 37561766fe9SRichard Henderson static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval) 37661766fe9SRichard Henderson { 37761766fe9SRichard Henderson if (unlikely(ival == -1)) { 37861766fe9SRichard Henderson tcg_gen_mov_tl(dest, vval); 37961766fe9SRichard Henderson } else { 38061766fe9SRichard Henderson tcg_gen_movi_tl(dest, ival); 38161766fe9SRichard Henderson } 38261766fe9SRichard Henderson } 38361766fe9SRichard Henderson 38461766fe9SRichard Henderson static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp) 38561766fe9SRichard Henderson { 38661766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 38761766fe9SRichard Henderson } 38861766fe9SRichard Henderson 38961766fe9SRichard Henderson static void gen_excp_1(int exception) 39061766fe9SRichard Henderson { 39161766fe9SRichard Henderson TCGv_i32 t = tcg_const_i32(exception); 39261766fe9SRichard Henderson gen_helper_excp(cpu_env, t); 39361766fe9SRichard Henderson tcg_temp_free_i32(t); 39461766fe9SRichard Henderson } 39561766fe9SRichard Henderson 39661766fe9SRichard Henderson static ExitStatus gen_excp(DisasContext *ctx, int exception) 39761766fe9SRichard Henderson { 39861766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 39961766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 400129e9cc3SRichard Henderson nullify_save(ctx); 40161766fe9SRichard Henderson gen_excp_1(exception); 40261766fe9SRichard Henderson return EXIT_NORETURN; 40361766fe9SRichard Henderson } 40461766fe9SRichard Henderson 40561766fe9SRichard Henderson static ExitStatus gen_illegal(DisasContext *ctx) 40661766fe9SRichard Henderson { 407129e9cc3SRichard Henderson nullify_over(ctx); 408129e9cc3SRichard Henderson return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL)); 40961766fe9SRichard Henderson } 41061766fe9SRichard Henderson 41161766fe9SRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ulong dest) 41261766fe9SRichard Henderson { 41361766fe9SRichard Henderson /* Suppress goto_tb in the case of single-steping and IO. */ 41461766fe9SRichard Henderson if ((ctx->tb->cflags & CF_LAST_IO) || ctx->singlestep_enabled) { 41561766fe9SRichard Henderson return false; 41661766fe9SRichard Henderson } 41761766fe9SRichard Henderson return true; 41861766fe9SRichard Henderson } 41961766fe9SRichard Henderson 420129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 421129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 422129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 423129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 424129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 425129e9cc3SRichard Henderson { 426129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 427129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 428129e9cc3SRichard Henderson } 429129e9cc3SRichard Henderson 43061766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 43161766fe9SRichard Henderson target_ulong f, target_ulong b) 43261766fe9SRichard Henderson { 43361766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 43461766fe9SRichard Henderson tcg_gen_goto_tb(which); 43561766fe9SRichard Henderson tcg_gen_movi_tl(cpu_iaoq_f, f); 43661766fe9SRichard Henderson tcg_gen_movi_tl(cpu_iaoq_b, b); 43761766fe9SRichard Henderson tcg_gen_exit_tb((uintptr_t)ctx->tb + which); 43861766fe9SRichard Henderson } else { 43961766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b); 44061766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var); 44161766fe9SRichard Henderson if (ctx->singlestep_enabled) { 44261766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 44361766fe9SRichard Henderson } else { 44461766fe9SRichard Henderson tcg_gen_exit_tb(0); 44561766fe9SRichard Henderson } 44661766fe9SRichard Henderson } 44761766fe9SRichard Henderson } 44861766fe9SRichard Henderson 449b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign, 450b2167459SRichard Henderson with the rest of the field becoming the least significant bits. */ 451b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len) 452b2167459SRichard Henderson { 453b2167459SRichard Henderson target_ulong x = -(target_ulong)extract32(val, pos, 1); 454b2167459SRichard Henderson x = (x << (len - 1)) | extract32(val, pos + 1, len - 1); 455b2167459SRichard Henderson return x; 456b2167459SRichard Henderson } 457b2167459SRichard Henderson 458*98cd9ca7SRichard Henderson static target_long assemble_12(uint32_t insn) 459*98cd9ca7SRichard Henderson { 460*98cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 461*98cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 462*98cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 463*98cd9ca7SRichard Henderson return x; 464*98cd9ca7SRichard Henderson } 465*98cd9ca7SRichard Henderson 466b2167459SRichard Henderson static target_long assemble_16(uint32_t insn) 467b2167459SRichard Henderson { 468b2167459SRichard Henderson /* Take the name from PA2.0, which produces a 16-bit number 469b2167459SRichard Henderson only with wide mode; otherwise a 14-bit number. Since we don't 470b2167459SRichard Henderson implement wide mode, this is always the 14-bit number. */ 471b2167459SRichard Henderson return low_sextract(insn, 0, 14); 472b2167459SRichard Henderson } 473b2167459SRichard Henderson 474*98cd9ca7SRichard Henderson static target_long assemble_17(uint32_t insn) 475*98cd9ca7SRichard Henderson { 476*98cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 477*98cd9ca7SRichard Henderson x = (x << 5) | extract32(insn, 16, 5); 478*98cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 479*98cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 480*98cd9ca7SRichard Henderson return x << 2; 481*98cd9ca7SRichard Henderson } 482*98cd9ca7SRichard Henderson 483b2167459SRichard Henderson static target_long assemble_21(uint32_t insn) 484b2167459SRichard Henderson { 485b2167459SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 486b2167459SRichard Henderson x = (x << 11) | extract32(insn, 1, 11); 487b2167459SRichard Henderson x = (x << 2) | extract32(insn, 14, 2); 488b2167459SRichard Henderson x = (x << 5) | extract32(insn, 16, 5); 489b2167459SRichard Henderson x = (x << 2) | extract32(insn, 12, 2); 490b2167459SRichard Henderson return x << 11; 491b2167459SRichard Henderson } 492b2167459SRichard Henderson 493*98cd9ca7SRichard Henderson static target_long assemble_22(uint32_t insn) 494*98cd9ca7SRichard Henderson { 495*98cd9ca7SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 496*98cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 16, 10); 497*98cd9ca7SRichard Henderson x = (x << 1) | extract32(insn, 2, 1); 498*98cd9ca7SRichard Henderson x = (x << 10) | extract32(insn, 3, 10); 499*98cd9ca7SRichard Henderson return x << 2; 500*98cd9ca7SRichard Henderson } 501*98cd9ca7SRichard Henderson 502b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of 503b2167459SRichard Henderson the conditions, without describing their exact implementation. The 504b2167459SRichard Henderson interpretations do not stand up well when considering ADD,C and SUB,B. 505b2167459SRichard Henderson However, considering the Addition, Subtraction and Logical conditions 506b2167459SRichard Henderson as a whole it would appear that these relations are similar to what 507b2167459SRichard Henderson a traditional NZCV set of flags would produce. */ 508b2167459SRichard Henderson 509b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv) 510b2167459SRichard Henderson { 511b2167459SRichard Henderson DisasCond cond; 512b2167459SRichard Henderson TCGv tmp; 513b2167459SRichard Henderson 514b2167459SRichard Henderson switch (cf >> 1) { 515b2167459SRichard Henderson case 0: /* Never / TR */ 516b2167459SRichard Henderson cond = cond_make_f(); 517b2167459SRichard Henderson break; 518b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 519b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 520b2167459SRichard Henderson break; 521b2167459SRichard Henderson case 2: /* < / >= (N / !N) */ 522b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, res); 523b2167459SRichard Henderson break; 524b2167459SRichard Henderson case 3: /* <= / > (N | Z / !N & !Z) */ 525b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LE, res); 526b2167459SRichard Henderson break; 527b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 528b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 529b2167459SRichard Henderson break; 530b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 531b2167459SRichard Henderson tmp = tcg_temp_new(); 532b2167459SRichard Henderson tcg_gen_neg_tl(tmp, cb_msb); 533b2167459SRichard Henderson tcg_gen_and_tl(tmp, tmp, res); 534b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, tmp); 535b2167459SRichard Henderson tcg_temp_free(tmp); 536b2167459SRichard Henderson break; 537b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 538b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 539b2167459SRichard Henderson break; 540b2167459SRichard Henderson case 7: /* OD / EV */ 541b2167459SRichard Henderson tmp = tcg_temp_new(); 542b2167459SRichard Henderson tcg_gen_andi_tl(tmp, res, 1); 543b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 544b2167459SRichard Henderson tcg_temp_free(tmp); 545b2167459SRichard Henderson break; 546b2167459SRichard Henderson default: 547b2167459SRichard Henderson g_assert_not_reached(); 548b2167459SRichard Henderson } 549b2167459SRichard Henderson if (cf & 1) { 550b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 551b2167459SRichard Henderson } 552b2167459SRichard Henderson 553b2167459SRichard Henderson return cond; 554b2167459SRichard Henderson } 555b2167459SRichard Henderson 556b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 557b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 558b2167459SRichard Henderson deleted as unused. */ 559b2167459SRichard Henderson 560b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv) 561b2167459SRichard Henderson { 562b2167459SRichard Henderson DisasCond cond; 563b2167459SRichard Henderson 564b2167459SRichard Henderson switch (cf >> 1) { 565b2167459SRichard Henderson case 1: /* = / <> */ 566b2167459SRichard Henderson cond = cond_make(TCG_COND_EQ, in1, in2); 567b2167459SRichard Henderson break; 568b2167459SRichard Henderson case 2: /* < / >= */ 569b2167459SRichard Henderson cond = cond_make(TCG_COND_LT, in1, in2); 570b2167459SRichard Henderson break; 571b2167459SRichard Henderson case 3: /* <= / > */ 572b2167459SRichard Henderson cond = cond_make(TCG_COND_LE, in1, in2); 573b2167459SRichard Henderson break; 574b2167459SRichard Henderson case 4: /* << / >>= */ 575b2167459SRichard Henderson cond = cond_make(TCG_COND_LTU, in1, in2); 576b2167459SRichard Henderson break; 577b2167459SRichard Henderson case 5: /* <<= / >> */ 578b2167459SRichard Henderson cond = cond_make(TCG_COND_LEU, in1, in2); 579b2167459SRichard Henderson break; 580b2167459SRichard Henderson default: 581b2167459SRichard Henderson return do_cond(cf, res, sv, sv); 582b2167459SRichard Henderson } 583b2167459SRichard Henderson if (cf & 1) { 584b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 585b2167459SRichard Henderson } 586b2167459SRichard Henderson 587b2167459SRichard Henderson return cond; 588b2167459SRichard Henderson } 589b2167459SRichard Henderson 590b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not 591b2167459SRichard Henderson computed, and use of them is undefined. */ 592b2167459SRichard Henderson 593b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res) 594b2167459SRichard Henderson { 595b2167459SRichard Henderson switch (cf >> 1) { 596b2167459SRichard Henderson case 4: case 5: case 6: 597b2167459SRichard Henderson cf &= 1; 598b2167459SRichard Henderson break; 599b2167459SRichard Henderson } 600b2167459SRichard Henderson return do_cond(cf, res, res, res); 601b2167459SRichard Henderson } 602b2167459SRichard Henderson 603*98cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 604*98cd9ca7SRichard Henderson 605*98cd9ca7SRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv res) 606*98cd9ca7SRichard Henderson { 607*98cd9ca7SRichard Henderson unsigned c, f; 608*98cd9ca7SRichard Henderson 609*98cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 610*98cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 611*98cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 612*98cd9ca7SRichard Henderson c = orig & 3; 613*98cd9ca7SRichard Henderson if (c == 3) { 614*98cd9ca7SRichard Henderson c = 7; 615*98cd9ca7SRichard Henderson } 616*98cd9ca7SRichard Henderson f = (orig & 4) / 4; 617*98cd9ca7SRichard Henderson 618*98cd9ca7SRichard Henderson return do_log_cond(c * 2 + f, res); 619*98cd9ca7SRichard Henderson } 620*98cd9ca7SRichard Henderson 621b2167459SRichard Henderson /* Similar, but for unit conditions. */ 622b2167459SRichard Henderson 623b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2) 624b2167459SRichard Henderson { 625b2167459SRichard Henderson DisasCond cond; 626b2167459SRichard Henderson TCGv tmp, cb; 627b2167459SRichard Henderson 628b2167459SRichard Henderson TCGV_UNUSED(cb); 629b2167459SRichard Henderson if (cf & 8) { 630b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 631b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 632b2167459SRichard Henderson * leaves us with carry bits spread across two words. 633b2167459SRichard Henderson */ 634b2167459SRichard Henderson cb = tcg_temp_new(); 635b2167459SRichard Henderson tmp = tcg_temp_new(); 636b2167459SRichard Henderson tcg_gen_or_tl(cb, in1, in2); 637b2167459SRichard Henderson tcg_gen_and_tl(tmp, in1, in2); 638b2167459SRichard Henderson tcg_gen_andc_tl(cb, cb, res); 639b2167459SRichard Henderson tcg_gen_or_tl(cb, cb, tmp); 640b2167459SRichard Henderson tcg_temp_free(tmp); 641b2167459SRichard Henderson } 642b2167459SRichard Henderson 643b2167459SRichard Henderson switch (cf >> 1) { 644b2167459SRichard Henderson case 0: /* never / TR */ 645b2167459SRichard Henderson case 1: /* undefined */ 646b2167459SRichard Henderson case 5: /* undefined */ 647b2167459SRichard Henderson cond = cond_make_f(); 648b2167459SRichard Henderson break; 649b2167459SRichard Henderson 650b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 651b2167459SRichard Henderson /* See hasless(v,1) from 652b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 653b2167459SRichard Henderson */ 654b2167459SRichard Henderson tmp = tcg_temp_new(); 655b2167459SRichard Henderson tcg_gen_subi_tl(tmp, res, 0x01010101u); 656b2167459SRichard Henderson tcg_gen_andc_tl(tmp, tmp, res); 657b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x80808080u); 658b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 659b2167459SRichard Henderson tcg_temp_free(tmp); 660b2167459SRichard Henderson break; 661b2167459SRichard Henderson 662b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 663b2167459SRichard Henderson tmp = tcg_temp_new(); 664b2167459SRichard Henderson tcg_gen_subi_tl(tmp, res, 0x00010001u); 665b2167459SRichard Henderson tcg_gen_andc_tl(tmp, tmp, res); 666b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x80008000u); 667b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 668b2167459SRichard Henderson tcg_temp_free(tmp); 669b2167459SRichard Henderson break; 670b2167459SRichard Henderson 671b2167459SRichard Henderson case 4: /* SDC / NDC */ 672b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x88888888u); 673b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 674b2167459SRichard Henderson break; 675b2167459SRichard Henderson 676b2167459SRichard Henderson case 6: /* SBC / NBC */ 677b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x80808080u); 678b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 679b2167459SRichard Henderson break; 680b2167459SRichard Henderson 681b2167459SRichard Henderson case 7: /* SHC / NHC */ 682b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x80008000u); 683b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 684b2167459SRichard Henderson break; 685b2167459SRichard Henderson 686b2167459SRichard Henderson default: 687b2167459SRichard Henderson g_assert_not_reached(); 688b2167459SRichard Henderson } 689b2167459SRichard Henderson if (cf & 8) { 690b2167459SRichard Henderson tcg_temp_free(cb); 691b2167459SRichard Henderson } 692b2167459SRichard Henderson if (cf & 1) { 693b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 694b2167459SRichard Henderson } 695b2167459SRichard Henderson 696b2167459SRichard Henderson return cond; 697b2167459SRichard Henderson } 698b2167459SRichard Henderson 699b2167459SRichard Henderson /* Compute signed overflow for addition. */ 700b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2) 701b2167459SRichard Henderson { 702b2167459SRichard Henderson TCGv sv = get_temp(ctx); 703b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 704b2167459SRichard Henderson 705b2167459SRichard Henderson tcg_gen_xor_tl(sv, res, in1); 706b2167459SRichard Henderson tcg_gen_xor_tl(tmp, in1, in2); 707b2167459SRichard Henderson tcg_gen_andc_tl(sv, sv, tmp); 708b2167459SRichard Henderson tcg_temp_free(tmp); 709b2167459SRichard Henderson 710b2167459SRichard Henderson return sv; 711b2167459SRichard Henderson } 712b2167459SRichard Henderson 713b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 714b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2) 715b2167459SRichard Henderson { 716b2167459SRichard Henderson TCGv sv = get_temp(ctx); 717b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 718b2167459SRichard Henderson 719b2167459SRichard Henderson tcg_gen_xor_tl(sv, res, in1); 720b2167459SRichard Henderson tcg_gen_xor_tl(tmp, in1, in2); 721b2167459SRichard Henderson tcg_gen_and_tl(sv, sv, tmp); 722b2167459SRichard Henderson tcg_temp_free(tmp); 723b2167459SRichard Henderson 724b2167459SRichard Henderson return sv; 725b2167459SRichard Henderson } 726b2167459SRichard Henderson 727b2167459SRichard Henderson static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 728b2167459SRichard Henderson unsigned shift, bool is_l, bool is_tsv, bool is_tc, 729b2167459SRichard Henderson bool is_c, unsigned cf) 730b2167459SRichard Henderson { 731b2167459SRichard Henderson TCGv dest, cb, cb_msb, sv, tmp; 732b2167459SRichard Henderson unsigned c = cf >> 1; 733b2167459SRichard Henderson DisasCond cond; 734b2167459SRichard Henderson 735b2167459SRichard Henderson dest = tcg_temp_new(); 736b2167459SRichard Henderson TCGV_UNUSED(cb); 737b2167459SRichard Henderson TCGV_UNUSED(cb_msb); 738b2167459SRichard Henderson 739b2167459SRichard Henderson if (shift) { 740b2167459SRichard Henderson tmp = get_temp(ctx); 741b2167459SRichard Henderson tcg_gen_shli_tl(tmp, in1, shift); 742b2167459SRichard Henderson in1 = tmp; 743b2167459SRichard Henderson } 744b2167459SRichard Henderson 745b2167459SRichard Henderson if (!is_l || c == 4 || c == 5) { 746b2167459SRichard Henderson TCGv zero = tcg_const_tl(0); 747b2167459SRichard Henderson cb_msb = get_temp(ctx); 748b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero); 749b2167459SRichard Henderson if (is_c) { 750b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero); 751b2167459SRichard Henderson } 752b2167459SRichard Henderson tcg_temp_free(zero); 753b2167459SRichard Henderson if (!is_l) { 754b2167459SRichard Henderson cb = get_temp(ctx); 755b2167459SRichard Henderson tcg_gen_xor_tl(cb, in1, in2); 756b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 757b2167459SRichard Henderson } 758b2167459SRichard Henderson } else { 759b2167459SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 760b2167459SRichard Henderson if (is_c) { 761b2167459SRichard Henderson tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb); 762b2167459SRichard Henderson } 763b2167459SRichard Henderson } 764b2167459SRichard Henderson 765b2167459SRichard Henderson /* Compute signed overflow if required. */ 766b2167459SRichard Henderson TCGV_UNUSED(sv); 767b2167459SRichard Henderson if (is_tsv || c == 6) { 768b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 769b2167459SRichard Henderson if (is_tsv) { 770b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 771b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 772b2167459SRichard Henderson } 773b2167459SRichard Henderson } 774b2167459SRichard Henderson 775b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 776b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 777b2167459SRichard Henderson if (is_tc) { 778b2167459SRichard Henderson cond_prep(&cond); 779b2167459SRichard Henderson tmp = tcg_temp_new(); 780b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 781b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 782b2167459SRichard Henderson tcg_temp_free(tmp); 783b2167459SRichard Henderson } 784b2167459SRichard Henderson 785b2167459SRichard Henderson /* Write back the result. */ 786b2167459SRichard Henderson if (!is_l) { 787b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 788b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 789b2167459SRichard Henderson } 790b2167459SRichard Henderson save_gpr(ctx, rt, dest); 791b2167459SRichard Henderson tcg_temp_free(dest); 792b2167459SRichard Henderson 793b2167459SRichard Henderson /* Install the new nullification. */ 794b2167459SRichard Henderson cond_free(&ctx->null_cond); 795b2167459SRichard Henderson ctx->null_cond = cond; 796b2167459SRichard Henderson return NO_EXIT; 797b2167459SRichard Henderson } 798b2167459SRichard Henderson 799b2167459SRichard Henderson static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 800b2167459SRichard Henderson bool is_tsv, bool is_b, bool is_tc, unsigned cf) 801b2167459SRichard Henderson { 802b2167459SRichard Henderson TCGv dest, sv, cb, cb_msb, zero, tmp; 803b2167459SRichard Henderson unsigned c = cf >> 1; 804b2167459SRichard Henderson DisasCond cond; 805b2167459SRichard Henderson 806b2167459SRichard Henderson dest = tcg_temp_new(); 807b2167459SRichard Henderson cb = tcg_temp_new(); 808b2167459SRichard Henderson cb_msb = tcg_temp_new(); 809b2167459SRichard Henderson 810b2167459SRichard Henderson zero = tcg_const_tl(0); 811b2167459SRichard Henderson if (is_b) { 812b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 813b2167459SRichard Henderson tcg_gen_not_tl(cb, in2); 814b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero); 815b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero); 816b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, in1); 817b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 818b2167459SRichard Henderson } else { 819b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 820b2167459SRichard Henderson operations by seeding the high word with 1 and subtracting. */ 821b2167459SRichard Henderson tcg_gen_movi_tl(cb_msb, 1); 822b2167459SRichard Henderson tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero); 823b2167459SRichard Henderson tcg_gen_eqv_tl(cb, in1, in2); 824b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 825b2167459SRichard Henderson } 826b2167459SRichard Henderson tcg_temp_free(zero); 827b2167459SRichard Henderson 828b2167459SRichard Henderson /* Compute signed overflow if required. */ 829b2167459SRichard Henderson TCGV_UNUSED(sv); 830b2167459SRichard Henderson if (is_tsv || c == 6) { 831b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 832b2167459SRichard Henderson if (is_tsv) { 833b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 834b2167459SRichard Henderson } 835b2167459SRichard Henderson } 836b2167459SRichard Henderson 837b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 838b2167459SRichard Henderson if (!is_b) { 839b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 840b2167459SRichard Henderson } else { 841b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 842b2167459SRichard Henderson } 843b2167459SRichard Henderson 844b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 845b2167459SRichard Henderson if (is_tc) { 846b2167459SRichard Henderson cond_prep(&cond); 847b2167459SRichard Henderson tmp = tcg_temp_new(); 848b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 849b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 850b2167459SRichard Henderson tcg_temp_free(tmp); 851b2167459SRichard Henderson } 852b2167459SRichard Henderson 853b2167459SRichard Henderson /* Write back the result. */ 854b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 855b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 856b2167459SRichard Henderson save_gpr(ctx, rt, dest); 857b2167459SRichard Henderson tcg_temp_free(dest); 858b2167459SRichard Henderson 859b2167459SRichard Henderson /* Install the new nullification. */ 860b2167459SRichard Henderson cond_free(&ctx->null_cond); 861b2167459SRichard Henderson ctx->null_cond = cond; 862b2167459SRichard Henderson return NO_EXIT; 863b2167459SRichard Henderson } 864b2167459SRichard Henderson 865b2167459SRichard Henderson static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1, 866b2167459SRichard Henderson TCGv in2, unsigned cf) 867b2167459SRichard Henderson { 868b2167459SRichard Henderson TCGv dest, sv; 869b2167459SRichard Henderson DisasCond cond; 870b2167459SRichard Henderson 871b2167459SRichard Henderson dest = tcg_temp_new(); 872b2167459SRichard Henderson tcg_gen_sub_tl(dest, in1, in2); 873b2167459SRichard Henderson 874b2167459SRichard Henderson /* Compute signed overflow if required. */ 875b2167459SRichard Henderson TCGV_UNUSED(sv); 876b2167459SRichard Henderson if ((cf >> 1) == 6) { 877b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 878b2167459SRichard Henderson } 879b2167459SRichard Henderson 880b2167459SRichard Henderson /* Form the condition for the compare. */ 881b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 882b2167459SRichard Henderson 883b2167459SRichard Henderson /* Clear. */ 884b2167459SRichard Henderson tcg_gen_movi_tl(dest, 0); 885b2167459SRichard Henderson save_gpr(ctx, rt, dest); 886b2167459SRichard Henderson tcg_temp_free(dest); 887b2167459SRichard Henderson 888b2167459SRichard Henderson /* Install the new nullification. */ 889b2167459SRichard Henderson cond_free(&ctx->null_cond); 890b2167459SRichard Henderson ctx->null_cond = cond; 891b2167459SRichard Henderson return NO_EXIT; 892b2167459SRichard Henderson } 893b2167459SRichard Henderson 894b2167459SRichard Henderson static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 895b2167459SRichard Henderson unsigned cf, void (*fn)(TCGv, TCGv, TCGv)) 896b2167459SRichard Henderson { 897b2167459SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 898b2167459SRichard Henderson 899b2167459SRichard Henderson /* Perform the operation, and writeback. */ 900b2167459SRichard Henderson fn(dest, in1, in2); 901b2167459SRichard Henderson save_gpr(ctx, rt, dest); 902b2167459SRichard Henderson 903b2167459SRichard Henderson /* Install the new nullification. */ 904b2167459SRichard Henderson cond_free(&ctx->null_cond); 905b2167459SRichard Henderson if (cf) { 906b2167459SRichard Henderson ctx->null_cond = do_log_cond(cf, dest); 907b2167459SRichard Henderson } 908b2167459SRichard Henderson return NO_EXIT; 909b2167459SRichard Henderson } 910b2167459SRichard Henderson 911b2167459SRichard Henderson static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1, 912b2167459SRichard Henderson TCGv in2, unsigned cf, bool is_tc, 913b2167459SRichard Henderson void (*fn)(TCGv, TCGv, TCGv)) 914b2167459SRichard Henderson { 915b2167459SRichard Henderson TCGv dest; 916b2167459SRichard Henderson DisasCond cond; 917b2167459SRichard Henderson 918b2167459SRichard Henderson if (cf == 0) { 919b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 920b2167459SRichard Henderson fn(dest, in1, in2); 921b2167459SRichard Henderson save_gpr(ctx, rt, dest); 922b2167459SRichard Henderson cond_free(&ctx->null_cond); 923b2167459SRichard Henderson } else { 924b2167459SRichard Henderson dest = tcg_temp_new(); 925b2167459SRichard Henderson fn(dest, in1, in2); 926b2167459SRichard Henderson 927b2167459SRichard Henderson cond = do_unit_cond(cf, dest, in1, in2); 928b2167459SRichard Henderson 929b2167459SRichard Henderson if (is_tc) { 930b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 931b2167459SRichard Henderson cond_prep(&cond); 932b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 933b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 934b2167459SRichard Henderson tcg_temp_free(tmp); 935b2167459SRichard Henderson } 936b2167459SRichard Henderson save_gpr(ctx, rt, dest); 937b2167459SRichard Henderson 938b2167459SRichard Henderson cond_free(&ctx->null_cond); 939b2167459SRichard Henderson ctx->null_cond = cond; 940b2167459SRichard Henderson } 941b2167459SRichard Henderson return NO_EXIT; 942b2167459SRichard Henderson } 943b2167459SRichard Henderson 944*98cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 945*98cd9ca7SRichard Henderson have already had nullification handled. */ 946*98cd9ca7SRichard Henderson static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest, 947*98cd9ca7SRichard Henderson unsigned link, bool is_n) 948*98cd9ca7SRichard Henderson { 949*98cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 950*98cd9ca7SRichard Henderson if (link != 0) { 951*98cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 952*98cd9ca7SRichard Henderson } 953*98cd9ca7SRichard Henderson ctx->iaoq_n = dest; 954*98cd9ca7SRichard Henderson if (is_n) { 955*98cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 956*98cd9ca7SRichard Henderson } 957*98cd9ca7SRichard Henderson return NO_EXIT; 958*98cd9ca7SRichard Henderson } else { 959*98cd9ca7SRichard Henderson nullify_over(ctx); 960*98cd9ca7SRichard Henderson 961*98cd9ca7SRichard Henderson if (link != 0) { 962*98cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 963*98cd9ca7SRichard Henderson } 964*98cd9ca7SRichard Henderson 965*98cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 966*98cd9ca7SRichard Henderson nullify_set(ctx, 0); 967*98cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 968*98cd9ca7SRichard Henderson } else { 969*98cd9ca7SRichard Henderson nullify_set(ctx, is_n); 970*98cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 971*98cd9ca7SRichard Henderson } 972*98cd9ca7SRichard Henderson 973*98cd9ca7SRichard Henderson nullify_end(ctx, NO_EXIT); 974*98cd9ca7SRichard Henderson 975*98cd9ca7SRichard Henderson nullify_set(ctx, 0); 976*98cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 977*98cd9ca7SRichard Henderson return EXIT_GOTO_TB; 978*98cd9ca7SRichard Henderson } 979*98cd9ca7SRichard Henderson } 980*98cd9ca7SRichard Henderson 981*98cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 982*98cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 983*98cd9ca7SRichard Henderson static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n, 984*98cd9ca7SRichard Henderson DisasCond *cond) 985*98cd9ca7SRichard Henderson { 986*98cd9ca7SRichard Henderson target_ulong dest = iaoq_dest(ctx, disp); 987*98cd9ca7SRichard Henderson TCGLabel *taken = NULL; 988*98cd9ca7SRichard Henderson TCGCond c = cond->c; 989*98cd9ca7SRichard Henderson int which = 0; 990*98cd9ca7SRichard Henderson bool n; 991*98cd9ca7SRichard Henderson 992*98cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 993*98cd9ca7SRichard Henderson 994*98cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 995*98cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 996*98cd9ca7SRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 997*98cd9ca7SRichard Henderson } 998*98cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 999*98cd9ca7SRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 1000*98cd9ca7SRichard Henderson } 1001*98cd9ca7SRichard Henderson 1002*98cd9ca7SRichard Henderson taken = gen_new_label(); 1003*98cd9ca7SRichard Henderson cond_prep(cond); 1004*98cd9ca7SRichard Henderson tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken); 1005*98cd9ca7SRichard Henderson cond_free(cond); 1006*98cd9ca7SRichard Henderson 1007*98cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 1008*98cd9ca7SRichard Henderson n = is_n && disp < 0; 1009*98cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 1010*98cd9ca7SRichard Henderson nullify_set(ctx, 0); 1011*98cd9ca7SRichard Henderson gen_goto_tb(ctx, which++, ctx->iaoq_n, ctx->iaoq_n + 4); 1012*98cd9ca7SRichard Henderson } else { 1013*98cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 1014*98cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 1015*98cd9ca7SRichard Henderson ctx->null_lab = NULL; 1016*98cd9ca7SRichard Henderson } 1017*98cd9ca7SRichard Henderson nullify_set(ctx, n); 1018*98cd9ca7SRichard Henderson gen_goto_tb(ctx, which++, ctx->iaoq_b, ctx->iaoq_n); 1019*98cd9ca7SRichard Henderson } 1020*98cd9ca7SRichard Henderson 1021*98cd9ca7SRichard Henderson gen_set_label(taken); 1022*98cd9ca7SRichard Henderson 1023*98cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 1024*98cd9ca7SRichard Henderson n = is_n && disp >= 0; 1025*98cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 1026*98cd9ca7SRichard Henderson nullify_set(ctx, 0); 1027*98cd9ca7SRichard Henderson gen_goto_tb(ctx, which++, dest, dest + 4); 1028*98cd9ca7SRichard Henderson } else { 1029*98cd9ca7SRichard Henderson nullify_set(ctx, n); 1030*98cd9ca7SRichard Henderson gen_goto_tb(ctx, which++, ctx->iaoq_b, dest); 1031*98cd9ca7SRichard Henderson } 1032*98cd9ca7SRichard Henderson 1033*98cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 1034*98cd9ca7SRichard Henderson if (ctx->null_lab) { 1035*98cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 1036*98cd9ca7SRichard Henderson ctx->null_lab = NULL; 1037*98cd9ca7SRichard Henderson if (which < 2) { 1038*98cd9ca7SRichard Henderson nullify_set(ctx, 0); 1039*98cd9ca7SRichard Henderson gen_goto_tb(ctx, which, ctx->iaoq_b, ctx->iaoq_n); 1040*98cd9ca7SRichard Henderson return EXIT_GOTO_TB; 1041*98cd9ca7SRichard Henderson } else { 1042*98cd9ca7SRichard Henderson return EXIT_IAQ_N_STALE; 1043*98cd9ca7SRichard Henderson } 1044*98cd9ca7SRichard Henderson } else { 1045*98cd9ca7SRichard Henderson return EXIT_GOTO_TB; 1046*98cd9ca7SRichard Henderson } 1047*98cd9ca7SRichard Henderson } 1048*98cd9ca7SRichard Henderson 1049*98cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 1050*98cd9ca7SRichard Henderson nullification of the branch itself. */ 1051*98cd9ca7SRichard Henderson static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest, 1052*98cd9ca7SRichard Henderson unsigned link, bool is_n) 1053*98cd9ca7SRichard Henderson { 1054*98cd9ca7SRichard Henderson TCGv a0, a1, next, tmp; 1055*98cd9ca7SRichard Henderson TCGCond c; 1056*98cd9ca7SRichard Henderson 1057*98cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 1058*98cd9ca7SRichard Henderson 1059*98cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 1060*98cd9ca7SRichard Henderson if (link != 0) { 1061*98cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 1062*98cd9ca7SRichard Henderson } 1063*98cd9ca7SRichard Henderson next = get_temp(ctx); 1064*98cd9ca7SRichard Henderson tcg_gen_mov_tl(next, dest); 1065*98cd9ca7SRichard Henderson ctx->iaoq_n = -1; 1066*98cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 1067*98cd9ca7SRichard Henderson if (is_n) { 1068*98cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 1069*98cd9ca7SRichard Henderson } 1070*98cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 1071*98cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 1072*98cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 1073*98cd9ca7SRichard Henderson tracepoint in effect). Since the exit_tb that we must use 1074*98cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 1075*98cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 1076*98cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 1077*98cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 1078*98cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 1079*98cd9ca7SRichard Henderson 1080*98cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 1081*98cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 1082*98cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 1083*98cd9ca7SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, dest); 1084*98cd9ca7SRichard Henderson tcg_gen_addi_tl(cpu_iaoq_b, dest, 4); 1085*98cd9ca7SRichard Henderson 1086*98cd9ca7SRichard Henderson nullify_over(ctx); 1087*98cd9ca7SRichard Henderson if (link != 0) { 1088*98cd9ca7SRichard Henderson tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n); 1089*98cd9ca7SRichard Henderson } 1090*98cd9ca7SRichard Henderson tcg_gen_exit_tb(0); 1091*98cd9ca7SRichard Henderson return nullify_end(ctx, NO_EXIT); 1092*98cd9ca7SRichard Henderson } else { 1093*98cd9ca7SRichard Henderson cond_prep(&ctx->null_cond); 1094*98cd9ca7SRichard Henderson c = ctx->null_cond.c; 1095*98cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 1096*98cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 1097*98cd9ca7SRichard Henderson 1098*98cd9ca7SRichard Henderson tmp = tcg_temp_new(); 1099*98cd9ca7SRichard Henderson next = get_temp(ctx); 1100*98cd9ca7SRichard Henderson 1101*98cd9ca7SRichard Henderson copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var); 1102*98cd9ca7SRichard Henderson tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest); 1103*98cd9ca7SRichard Henderson ctx->iaoq_n = -1; 1104*98cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 1105*98cd9ca7SRichard Henderson 1106*98cd9ca7SRichard Henderson if (link != 0) { 1107*98cd9ca7SRichard Henderson tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 1108*98cd9ca7SRichard Henderson } 1109*98cd9ca7SRichard Henderson 1110*98cd9ca7SRichard Henderson if (is_n) { 1111*98cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 1112*98cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 1113*98cd9ca7SRichard Henderson to the branch. */ 1114*98cd9ca7SRichard Henderson tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1); 1115*98cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 1116*98cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 1117*98cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 1118*98cd9ca7SRichard Henderson } else { 1119*98cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 1120*98cd9ca7SRichard Henderson } 1121*98cd9ca7SRichard Henderson } 1122*98cd9ca7SRichard Henderson 1123*98cd9ca7SRichard Henderson return NO_EXIT; 1124*98cd9ca7SRichard Henderson } 1125*98cd9ca7SRichard Henderson 1126b2167459SRichard Henderson static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn, 1127b2167459SRichard Henderson const DisasInsn *di) 1128b2167459SRichard Henderson { 1129b2167459SRichard Henderson cond_free(&ctx->null_cond); 1130b2167459SRichard Henderson return NO_EXIT; 1131b2167459SRichard Henderson } 1132b2167459SRichard Henderson 1133b2167459SRichard Henderson static ExitStatus trans_add(DisasContext *ctx, uint32_t insn, 1134b2167459SRichard Henderson const DisasInsn *di) 1135b2167459SRichard Henderson { 1136b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1137b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1138b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1139b2167459SRichard Henderson unsigned ext = extract32(insn, 8, 4); 1140b2167459SRichard Henderson unsigned shift = extract32(insn, 6, 2); 1141b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1142b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1143b2167459SRichard Henderson bool is_c = false; 1144b2167459SRichard Henderson bool is_l = false; 1145b2167459SRichard Henderson bool is_tc = false; 1146b2167459SRichard Henderson bool is_tsv = false; 1147b2167459SRichard Henderson ExitStatus ret; 1148b2167459SRichard Henderson 1149b2167459SRichard Henderson switch (ext) { 1150b2167459SRichard Henderson case 0x6: /* ADD, SHLADD */ 1151b2167459SRichard Henderson break; 1152b2167459SRichard Henderson case 0xa: /* ADD,L, SHLADD,L */ 1153b2167459SRichard Henderson is_l = true; 1154b2167459SRichard Henderson break; 1155b2167459SRichard Henderson case 0xe: /* ADD,TSV, SHLADD,TSV (1) */ 1156b2167459SRichard Henderson is_tsv = true; 1157b2167459SRichard Henderson break; 1158b2167459SRichard Henderson case 0x7: /* ADD,C */ 1159b2167459SRichard Henderson is_c = true; 1160b2167459SRichard Henderson break; 1161b2167459SRichard Henderson case 0xf: /* ADD,C,TSV */ 1162b2167459SRichard Henderson is_c = is_tsv = true; 1163b2167459SRichard Henderson break; 1164b2167459SRichard Henderson default: 1165b2167459SRichard Henderson return gen_illegal(ctx); 1166b2167459SRichard Henderson } 1167b2167459SRichard Henderson 1168b2167459SRichard Henderson if (cf) { 1169b2167459SRichard Henderson nullify_over(ctx); 1170b2167459SRichard Henderson } 1171b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1172b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1173b2167459SRichard Henderson ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf); 1174b2167459SRichard Henderson return nullify_end(ctx, ret); 1175b2167459SRichard Henderson } 1176b2167459SRichard Henderson 1177b2167459SRichard Henderson static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn, 1178b2167459SRichard Henderson const DisasInsn *di) 1179b2167459SRichard Henderson { 1180b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1181b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1182b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1183b2167459SRichard Henderson unsigned ext = extract32(insn, 6, 6); 1184b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1185b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1186b2167459SRichard Henderson bool is_b = false; 1187b2167459SRichard Henderson bool is_tc = false; 1188b2167459SRichard Henderson bool is_tsv = false; 1189b2167459SRichard Henderson ExitStatus ret; 1190b2167459SRichard Henderson 1191b2167459SRichard Henderson switch (ext) { 1192b2167459SRichard Henderson case 0x10: /* SUB */ 1193b2167459SRichard Henderson break; 1194b2167459SRichard Henderson case 0x30: /* SUB,TSV */ 1195b2167459SRichard Henderson is_tsv = true; 1196b2167459SRichard Henderson break; 1197b2167459SRichard Henderson case 0x14: /* SUB,B */ 1198b2167459SRichard Henderson is_b = true; 1199b2167459SRichard Henderson break; 1200b2167459SRichard Henderson case 0x34: /* SUB,B,TSV */ 1201b2167459SRichard Henderson is_b = is_tsv = true; 1202b2167459SRichard Henderson break; 1203b2167459SRichard Henderson case 0x13: /* SUB,TC */ 1204b2167459SRichard Henderson is_tc = true; 1205b2167459SRichard Henderson break; 1206b2167459SRichard Henderson case 0x33: /* SUB,TSV,TC */ 1207b2167459SRichard Henderson is_tc = is_tsv = true; 1208b2167459SRichard Henderson break; 1209b2167459SRichard Henderson default: 1210b2167459SRichard Henderson return gen_illegal(ctx); 1211b2167459SRichard Henderson } 1212b2167459SRichard Henderson 1213b2167459SRichard Henderson if (cf) { 1214b2167459SRichard Henderson nullify_over(ctx); 1215b2167459SRichard Henderson } 1216b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1217b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1218b2167459SRichard Henderson ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf); 1219b2167459SRichard Henderson return nullify_end(ctx, ret); 1220b2167459SRichard Henderson } 1221b2167459SRichard Henderson 1222b2167459SRichard Henderson static ExitStatus trans_log(DisasContext *ctx, uint32_t insn, 1223b2167459SRichard Henderson const DisasInsn *di) 1224b2167459SRichard Henderson { 1225b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1226b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1227b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1228b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1229b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1230b2167459SRichard Henderson ExitStatus ret; 1231b2167459SRichard Henderson 1232b2167459SRichard Henderson if (cf) { 1233b2167459SRichard Henderson nullify_over(ctx); 1234b2167459SRichard Henderson } 1235b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1236b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1237b2167459SRichard Henderson ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f_ttt); 1238b2167459SRichard Henderson return nullify_end(ctx, ret); 1239b2167459SRichard Henderson } 1240b2167459SRichard Henderson 1241b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */ 1242b2167459SRichard Henderson static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn, 1243b2167459SRichard Henderson const DisasInsn *di) 1244b2167459SRichard Henderson { 1245b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1246b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1247b2167459SRichard Henderson 1248b2167459SRichard Henderson if (r1 == 0) { 1249b2167459SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 1250b2167459SRichard Henderson tcg_gen_movi_tl(dest, 0); 1251b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1252b2167459SRichard Henderson } else { 1253b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 1254b2167459SRichard Henderson } 1255b2167459SRichard Henderson cond_free(&ctx->null_cond); 1256b2167459SRichard Henderson return NO_EXIT; 1257b2167459SRichard Henderson } 1258b2167459SRichard Henderson 1259b2167459SRichard Henderson static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn, 1260b2167459SRichard Henderson const DisasInsn *di) 1261b2167459SRichard Henderson { 1262b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1263b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1264b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1265b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1266b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1267b2167459SRichard Henderson ExitStatus ret; 1268b2167459SRichard Henderson 1269b2167459SRichard Henderson if (cf) { 1270b2167459SRichard Henderson nullify_over(ctx); 1271b2167459SRichard Henderson } 1272b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1273b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1274b2167459SRichard Henderson ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf); 1275b2167459SRichard Henderson return nullify_end(ctx, ret); 1276b2167459SRichard Henderson } 1277b2167459SRichard Henderson 1278b2167459SRichard Henderson static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn, 1279b2167459SRichard Henderson const DisasInsn *di) 1280b2167459SRichard Henderson { 1281b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1282b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1283b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1284b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1285b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1286b2167459SRichard Henderson ExitStatus ret; 1287b2167459SRichard Henderson 1288b2167459SRichard Henderson if (cf) { 1289b2167459SRichard Henderson nullify_over(ctx); 1290b2167459SRichard Henderson } 1291b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1292b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1293b2167459SRichard Henderson ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl); 1294b2167459SRichard Henderson return nullify_end(ctx, ret); 1295b2167459SRichard Henderson } 1296b2167459SRichard Henderson 1297b2167459SRichard Henderson static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn, 1298b2167459SRichard Henderson const DisasInsn *di) 1299b2167459SRichard Henderson { 1300b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1301b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1302b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1303b2167459SRichard Henderson unsigned is_tc = extract32(insn, 6, 1); 1304b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1305b2167459SRichard Henderson TCGv tcg_r1, tcg_r2, tmp; 1306b2167459SRichard Henderson ExitStatus ret; 1307b2167459SRichard Henderson 1308b2167459SRichard Henderson if (cf) { 1309b2167459SRichard Henderson nullify_over(ctx); 1310b2167459SRichard Henderson } 1311b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1312b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1313b2167459SRichard Henderson tmp = get_temp(ctx); 1314b2167459SRichard Henderson tcg_gen_not_tl(tmp, tcg_r2); 1315b2167459SRichard Henderson ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl); 1316b2167459SRichard Henderson return nullify_end(ctx, ret); 1317b2167459SRichard Henderson } 1318b2167459SRichard Henderson 1319b2167459SRichard Henderson static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn, 1320b2167459SRichard Henderson const DisasInsn *di) 1321b2167459SRichard Henderson { 1322b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1323b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1324b2167459SRichard Henderson unsigned is_i = extract32(insn, 6, 1); 1325b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1326b2167459SRichard Henderson TCGv tmp; 1327b2167459SRichard Henderson ExitStatus ret; 1328b2167459SRichard Henderson 1329b2167459SRichard Henderson nullify_over(ctx); 1330b2167459SRichard Henderson 1331b2167459SRichard Henderson tmp = get_temp(ctx); 1332b2167459SRichard Henderson tcg_gen_shri_tl(tmp, cpu_psw_cb, 3); 1333b2167459SRichard Henderson if (!is_i) { 1334b2167459SRichard Henderson tcg_gen_not_tl(tmp, tmp); 1335b2167459SRichard Henderson } 1336b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x11111111); 1337b2167459SRichard Henderson tcg_gen_muli_tl(tmp, tmp, 6); 1338b2167459SRichard Henderson ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false, 1339b2167459SRichard Henderson is_i ? tcg_gen_add_tl : tcg_gen_sub_tl); 1340b2167459SRichard Henderson 1341b2167459SRichard Henderson return nullify_end(ctx, ret); 1342b2167459SRichard Henderson } 1343b2167459SRichard Henderson 1344b2167459SRichard Henderson static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn, 1345b2167459SRichard Henderson const DisasInsn *di) 1346b2167459SRichard Henderson { 1347b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1348b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1349b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1350b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1351b2167459SRichard Henderson TCGv dest, add1, add2, addc, zero, in1, in2; 1352b2167459SRichard Henderson 1353b2167459SRichard Henderson nullify_over(ctx); 1354b2167459SRichard Henderson 1355b2167459SRichard Henderson in1 = load_gpr(ctx, r1); 1356b2167459SRichard Henderson in2 = load_gpr(ctx, r2); 1357b2167459SRichard Henderson 1358b2167459SRichard Henderson add1 = tcg_temp_new(); 1359b2167459SRichard Henderson add2 = tcg_temp_new(); 1360b2167459SRichard Henderson addc = tcg_temp_new(); 1361b2167459SRichard Henderson dest = tcg_temp_new(); 1362b2167459SRichard Henderson zero = tcg_const_tl(0); 1363b2167459SRichard Henderson 1364b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 1365b2167459SRichard Henderson tcg_gen_add_tl(add1, in1, in1); 1366b2167459SRichard Henderson tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb); 1367b2167459SRichard Henderson 1368b2167459SRichard Henderson /* Add or subtract R2, depending on PSW[V]. Proper computation of 1369b2167459SRichard Henderson carry{8} requires that we subtract via + ~R2 + 1, as described in 1370b2167459SRichard Henderson the manual. By extracting and masking V, we can produce the 1371b2167459SRichard Henderson proper inputs to the addition without movcond. */ 1372b2167459SRichard Henderson tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1); 1373b2167459SRichard Henderson tcg_gen_xor_tl(add2, in2, addc); 1374b2167459SRichard Henderson tcg_gen_andi_tl(addc, addc, 1); 1375b2167459SRichard Henderson /* ??? This is only correct for 32-bit. */ 1376b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero); 1377b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero); 1378b2167459SRichard Henderson 1379b2167459SRichard Henderson tcg_temp_free(addc); 1380b2167459SRichard Henderson tcg_temp_free(zero); 1381b2167459SRichard Henderson 1382b2167459SRichard Henderson /* Write back the result register. */ 1383b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1384b2167459SRichard Henderson 1385b2167459SRichard Henderson /* Write back PSW[CB]. */ 1386b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_cb, add1, add2); 1387b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest); 1388b2167459SRichard Henderson 1389b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 1390b2167459SRichard Henderson tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb); 1391b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2); 1392b2167459SRichard Henderson 1393b2167459SRichard Henderson /* Install the new nullification. */ 1394b2167459SRichard Henderson if (cf) { 1395b2167459SRichard Henderson TCGv sv; 1396b2167459SRichard Henderson TCGV_UNUSED(sv); 1397b2167459SRichard Henderson if (cf >> 1 == 6) { 1398b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 1399b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 1400b2167459SRichard Henderson } 1401b2167459SRichard Henderson ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv); 1402b2167459SRichard Henderson } 1403b2167459SRichard Henderson 1404b2167459SRichard Henderson tcg_temp_free(add1); 1405b2167459SRichard Henderson tcg_temp_free(add2); 1406b2167459SRichard Henderson tcg_temp_free(dest); 1407b2167459SRichard Henderson 1408b2167459SRichard Henderson return nullify_end(ctx, NO_EXIT); 1409b2167459SRichard Henderson } 1410b2167459SRichard Henderson 1411b2167459SRichard Henderson static const DisasInsn table_arith_log[] = { 1412b2167459SRichard Henderson { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */ 1413b2167459SRichard Henderson { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */ 1414b2167459SRichard Henderson { 0x08000000u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_andc_tl }, 1415b2167459SRichard Henderson { 0x08000200u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_and_tl }, 1416b2167459SRichard Henderson { 0x08000240u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_or_tl }, 1417b2167459SRichard Henderson { 0x08000280u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_xor_tl }, 1418b2167459SRichard Henderson { 0x08000880u, 0xfc000fe0u, trans_cmpclr }, 1419b2167459SRichard Henderson { 0x08000380u, 0xfc000fe0u, trans_uxor }, 1420b2167459SRichard Henderson { 0x08000980u, 0xfc000fa0u, trans_uaddcm }, 1421b2167459SRichard Henderson { 0x08000b80u, 0xfc1f0fa0u, trans_dcor }, 1422b2167459SRichard Henderson { 0x08000440u, 0xfc000fe0u, trans_ds }, 1423b2167459SRichard Henderson { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */ 1424b2167459SRichard Henderson { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */ 1425b2167459SRichard Henderson { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */ 1426b2167459SRichard Henderson { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */ 1427b2167459SRichard Henderson }; 1428b2167459SRichard Henderson 1429b2167459SRichard Henderson static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn) 1430b2167459SRichard Henderson { 1431b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1432b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 1433b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1434b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1435b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1436b2167459SRichard Henderson unsigned o1 = extract32(insn, 26, 1); 1437b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1438b2167459SRichard Henderson ExitStatus ret; 1439b2167459SRichard Henderson 1440b2167459SRichard Henderson if (cf) { 1441b2167459SRichard Henderson nullify_over(ctx); 1442b2167459SRichard Henderson } 1443b2167459SRichard Henderson 1444b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1445b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1446b2167459SRichard Henderson ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf); 1447b2167459SRichard Henderson 1448b2167459SRichard Henderson return nullify_end(ctx, ret); 1449b2167459SRichard Henderson } 1450b2167459SRichard Henderson 1451b2167459SRichard Henderson static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn) 1452b2167459SRichard Henderson { 1453b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1454b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 1455b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1456b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1457b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1458b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1459b2167459SRichard Henderson ExitStatus ret; 1460b2167459SRichard Henderson 1461b2167459SRichard Henderson if (cf) { 1462b2167459SRichard Henderson nullify_over(ctx); 1463b2167459SRichard Henderson } 1464b2167459SRichard Henderson 1465b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1466b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1467b2167459SRichard Henderson ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf); 1468b2167459SRichard Henderson 1469b2167459SRichard Henderson return nullify_end(ctx, ret); 1470b2167459SRichard Henderson } 1471b2167459SRichard Henderson 1472b2167459SRichard Henderson static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn) 1473b2167459SRichard Henderson { 1474b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1475b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1476b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1477b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1478b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1479b2167459SRichard Henderson ExitStatus ret; 1480b2167459SRichard Henderson 1481b2167459SRichard Henderson if (cf) { 1482b2167459SRichard Henderson nullify_over(ctx); 1483b2167459SRichard Henderson } 1484b2167459SRichard Henderson 1485b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1486b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1487b2167459SRichard Henderson ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf); 1488b2167459SRichard Henderson 1489b2167459SRichard Henderson return nullify_end(ctx, ret); 1490b2167459SRichard Henderson } 1491b2167459SRichard Henderson 1492b2167459SRichard Henderson static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn) 1493b2167459SRichard Henderson { 1494b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 1495b2167459SRichard Henderson target_long i = assemble_21(insn); 1496b2167459SRichard Henderson TCGv tcg_rt = dest_gpr(ctx, rt); 1497b2167459SRichard Henderson 1498b2167459SRichard Henderson tcg_gen_movi_tl(tcg_rt, i); 1499b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 1500b2167459SRichard Henderson cond_free(&ctx->null_cond); 1501b2167459SRichard Henderson 1502b2167459SRichard Henderson return NO_EXIT; 1503b2167459SRichard Henderson } 1504b2167459SRichard Henderson 1505b2167459SRichard Henderson static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn) 1506b2167459SRichard Henderson { 1507b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 1508b2167459SRichard Henderson target_long i = assemble_21(insn); 1509b2167459SRichard Henderson TCGv tcg_rt = load_gpr(ctx, rt); 1510b2167459SRichard Henderson TCGv tcg_r1 = dest_gpr(ctx, 1); 1511b2167459SRichard Henderson 1512b2167459SRichard Henderson tcg_gen_addi_tl(tcg_r1, tcg_rt, i); 1513b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 1514b2167459SRichard Henderson cond_free(&ctx->null_cond); 1515b2167459SRichard Henderson 1516b2167459SRichard Henderson return NO_EXIT; 1517b2167459SRichard Henderson } 1518b2167459SRichard Henderson 1519b2167459SRichard Henderson static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn) 1520b2167459SRichard Henderson { 1521b2167459SRichard Henderson unsigned rb = extract32(insn, 21, 5); 1522b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1523b2167459SRichard Henderson target_long i = assemble_16(insn); 1524b2167459SRichard Henderson TCGv tcg_rt = dest_gpr(ctx, rt); 1525b2167459SRichard Henderson 1526b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 1527b2167459SRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */ 1528b2167459SRichard Henderson if (rb == 0) { 1529b2167459SRichard Henderson tcg_gen_movi_tl(tcg_rt, i); 1530b2167459SRichard Henderson } else { 1531b2167459SRichard Henderson tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i); 1532b2167459SRichard Henderson } 1533b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 1534b2167459SRichard Henderson cond_free(&ctx->null_cond); 1535b2167459SRichard Henderson 1536b2167459SRichard Henderson return NO_EXIT; 1537b2167459SRichard Henderson } 1538b2167459SRichard Henderson 1539*98cd9ca7SRichard Henderson static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn, 1540*98cd9ca7SRichard Henderson bool is_true, bool is_imm, bool is_dw) 1541*98cd9ca7SRichard Henderson { 1542*98cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 1543*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1544*98cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 1545*98cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 1546*98cd9ca7SRichard Henderson unsigned cf = c * 2 + !is_true; 1547*98cd9ca7SRichard Henderson TCGv dest, in1, in2, sv; 1548*98cd9ca7SRichard Henderson DisasCond cond; 1549*98cd9ca7SRichard Henderson 1550*98cd9ca7SRichard Henderson nullify_over(ctx); 1551*98cd9ca7SRichard Henderson 1552*98cd9ca7SRichard Henderson if (is_imm) { 1553*98cd9ca7SRichard Henderson in1 = load_const(ctx, low_sextract(insn, 16, 5)); 1554*98cd9ca7SRichard Henderson } else { 1555*98cd9ca7SRichard Henderson in1 = load_gpr(ctx, extract32(insn, 16, 5)); 1556*98cd9ca7SRichard Henderson } 1557*98cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 1558*98cd9ca7SRichard Henderson dest = get_temp(ctx); 1559*98cd9ca7SRichard Henderson 1560*98cd9ca7SRichard Henderson tcg_gen_sub_tl(dest, in1, in2); 1561*98cd9ca7SRichard Henderson 1562*98cd9ca7SRichard Henderson TCGV_UNUSED(sv); 1563*98cd9ca7SRichard Henderson if (c == 6) { 1564*98cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1565*98cd9ca7SRichard Henderson } 1566*98cd9ca7SRichard Henderson 1567*98cd9ca7SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 1568*98cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 1569*98cd9ca7SRichard Henderson } 1570*98cd9ca7SRichard Henderson 1571*98cd9ca7SRichard Henderson static ExitStatus trans_addb(DisasContext *ctx, uint32_t insn, 1572*98cd9ca7SRichard Henderson bool is_true, bool is_imm) 1573*98cd9ca7SRichard Henderson { 1574*98cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 1575*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1576*98cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 1577*98cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 1578*98cd9ca7SRichard Henderson unsigned cf = c * 2 + !is_true; 1579*98cd9ca7SRichard Henderson TCGv dest, in1, in2, sv, cb_msb; 1580*98cd9ca7SRichard Henderson DisasCond cond; 1581*98cd9ca7SRichard Henderson 1582*98cd9ca7SRichard Henderson nullify_over(ctx); 1583*98cd9ca7SRichard Henderson 1584*98cd9ca7SRichard Henderson if (is_imm) { 1585*98cd9ca7SRichard Henderson in1 = load_const(ctx, low_sextract(insn, 16, 5)); 1586*98cd9ca7SRichard Henderson } else { 1587*98cd9ca7SRichard Henderson in1 = load_gpr(ctx, extract32(insn, 16, 5)); 1588*98cd9ca7SRichard Henderson } 1589*98cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 1590*98cd9ca7SRichard Henderson dest = dest_gpr(ctx, r); 1591*98cd9ca7SRichard Henderson TCGV_UNUSED(sv); 1592*98cd9ca7SRichard Henderson TCGV_UNUSED(cb_msb); 1593*98cd9ca7SRichard Henderson 1594*98cd9ca7SRichard Henderson switch (c) { 1595*98cd9ca7SRichard Henderson default: 1596*98cd9ca7SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 1597*98cd9ca7SRichard Henderson break; 1598*98cd9ca7SRichard Henderson case 4: case 5: 1599*98cd9ca7SRichard Henderson cb_msb = get_temp(ctx); 1600*98cd9ca7SRichard Henderson tcg_gen_movi_tl(cb_msb, 0); 1601*98cd9ca7SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb); 1602*98cd9ca7SRichard Henderson break; 1603*98cd9ca7SRichard Henderson case 6: 1604*98cd9ca7SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 1605*98cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 1606*98cd9ca7SRichard Henderson break; 1607*98cd9ca7SRichard Henderson } 1608*98cd9ca7SRichard Henderson 1609*98cd9ca7SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 1610*98cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 1611*98cd9ca7SRichard Henderson } 1612*98cd9ca7SRichard Henderson 1613*98cd9ca7SRichard Henderson static ExitStatus trans_bb(DisasContext *ctx, uint32_t insn) 1614*98cd9ca7SRichard Henderson { 1615*98cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 1616*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1617*98cd9ca7SRichard Henderson unsigned c = extract32(insn, 15, 1); 1618*98cd9ca7SRichard Henderson unsigned r = extract32(insn, 16, 5); 1619*98cd9ca7SRichard Henderson unsigned p = extract32(insn, 21, 5); 1620*98cd9ca7SRichard Henderson unsigned i = extract32(insn, 26, 1); 1621*98cd9ca7SRichard Henderson TCGv tmp, tcg_r; 1622*98cd9ca7SRichard Henderson DisasCond cond; 1623*98cd9ca7SRichard Henderson 1624*98cd9ca7SRichard Henderson nullify_over(ctx); 1625*98cd9ca7SRichard Henderson 1626*98cd9ca7SRichard Henderson tmp = tcg_temp_new(); 1627*98cd9ca7SRichard Henderson tcg_r = load_gpr(ctx, r); 1628*98cd9ca7SRichard Henderson if (i) { 1629*98cd9ca7SRichard Henderson tcg_gen_shli_tl(tmp, tcg_r, p); 1630*98cd9ca7SRichard Henderson } else { 1631*98cd9ca7SRichard Henderson tcg_gen_shl_tl(tmp, tcg_r, cpu_sar); 1632*98cd9ca7SRichard Henderson } 1633*98cd9ca7SRichard Henderson 1634*98cd9ca7SRichard Henderson cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp); 1635*98cd9ca7SRichard Henderson tcg_temp_free(tmp); 1636*98cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 1637*98cd9ca7SRichard Henderson } 1638*98cd9ca7SRichard Henderson 1639*98cd9ca7SRichard Henderson static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm) 1640*98cd9ca7SRichard Henderson { 1641*98cd9ca7SRichard Henderson target_long disp = assemble_12(insn) * 4; 1642*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1643*98cd9ca7SRichard Henderson unsigned c = extract32(insn, 13, 3); 1644*98cd9ca7SRichard Henderson unsigned t = extract32(insn, 16, 5); 1645*98cd9ca7SRichard Henderson unsigned r = extract32(insn, 21, 5); 1646*98cd9ca7SRichard Henderson TCGv dest; 1647*98cd9ca7SRichard Henderson DisasCond cond; 1648*98cd9ca7SRichard Henderson 1649*98cd9ca7SRichard Henderson nullify_over(ctx); 1650*98cd9ca7SRichard Henderson 1651*98cd9ca7SRichard Henderson dest = dest_gpr(ctx, r); 1652*98cd9ca7SRichard Henderson if (is_imm) { 1653*98cd9ca7SRichard Henderson tcg_gen_movi_tl(dest, low_sextract(t, 0, 5)); 1654*98cd9ca7SRichard Henderson } else if (t == 0) { 1655*98cd9ca7SRichard Henderson tcg_gen_movi_tl(dest, 0); 1656*98cd9ca7SRichard Henderson } else { 1657*98cd9ca7SRichard Henderson tcg_gen_mov_tl(dest, cpu_gr[t]); 1658*98cd9ca7SRichard Henderson } 1659*98cd9ca7SRichard Henderson 1660*98cd9ca7SRichard Henderson cond = do_sed_cond(c, dest); 1661*98cd9ca7SRichard Henderson return do_cbranch(ctx, disp, n, &cond); 1662*98cd9ca7SRichard Henderson } 1663*98cd9ca7SRichard Henderson 1664*98cd9ca7SRichard Henderson static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l) 1665*98cd9ca7SRichard Henderson { 1666*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1667*98cd9ca7SRichard Henderson unsigned b = extract32(insn, 21, 5); 1668*98cd9ca7SRichard Henderson target_long disp = assemble_17(insn); 1669*98cd9ca7SRichard Henderson 1670*98cd9ca7SRichard Henderson /* unsigned s = low_uextract(insn, 13, 3); */ 1671*98cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 1672*98cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 1673*98cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 1674*98cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 1675*98cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 1676*98cd9ca7SRichard Henderson 1677*98cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 1678*98cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 1679*98cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 1680*98cd9ca7SRichard Henderson if (b == 0) { 1681*98cd9ca7SRichard Henderson return do_dbranch(ctx, disp, is_l ? 31 : 0, n); 1682*98cd9ca7SRichard Henderson } else { 1683*98cd9ca7SRichard Henderson TCGv tmp = get_temp(ctx); 1684*98cd9ca7SRichard Henderson tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp); 1685*98cd9ca7SRichard Henderson return do_ibranch(ctx, tmp, is_l ? 31 : 0, n); 1686*98cd9ca7SRichard Henderson } 1687*98cd9ca7SRichard Henderson } 1688*98cd9ca7SRichard Henderson 1689*98cd9ca7SRichard Henderson static ExitStatus trans_bl(DisasContext *ctx, uint32_t insn, 1690*98cd9ca7SRichard Henderson const DisasInsn *di) 1691*98cd9ca7SRichard Henderson { 1692*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1693*98cd9ca7SRichard Henderson unsigned link = extract32(insn, 21, 5); 1694*98cd9ca7SRichard Henderson target_long disp = assemble_17(insn); 1695*98cd9ca7SRichard Henderson 1696*98cd9ca7SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n); 1697*98cd9ca7SRichard Henderson } 1698*98cd9ca7SRichard Henderson 1699*98cd9ca7SRichard Henderson static ExitStatus trans_bl_long(DisasContext *ctx, uint32_t insn, 1700*98cd9ca7SRichard Henderson const DisasInsn *di) 1701*98cd9ca7SRichard Henderson { 1702*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1703*98cd9ca7SRichard Henderson target_long disp = assemble_22(insn); 1704*98cd9ca7SRichard Henderson 1705*98cd9ca7SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n); 1706*98cd9ca7SRichard Henderson } 1707*98cd9ca7SRichard Henderson 1708*98cd9ca7SRichard Henderson static ExitStatus trans_blr(DisasContext *ctx, uint32_t insn, 1709*98cd9ca7SRichard Henderson const DisasInsn *di) 1710*98cd9ca7SRichard Henderson { 1711*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1712*98cd9ca7SRichard Henderson unsigned rx = extract32(insn, 16, 5); 1713*98cd9ca7SRichard Henderson unsigned link = extract32(insn, 21, 5); 1714*98cd9ca7SRichard Henderson TCGv tmp = get_temp(ctx); 1715*98cd9ca7SRichard Henderson 1716*98cd9ca7SRichard Henderson tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3); 1717*98cd9ca7SRichard Henderson tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8); 1718*98cd9ca7SRichard Henderson return do_ibranch(ctx, tmp, link, n); 1719*98cd9ca7SRichard Henderson } 1720*98cd9ca7SRichard Henderson 1721*98cd9ca7SRichard Henderson static ExitStatus trans_bv(DisasContext *ctx, uint32_t insn, 1722*98cd9ca7SRichard Henderson const DisasInsn *di) 1723*98cd9ca7SRichard Henderson { 1724*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1725*98cd9ca7SRichard Henderson unsigned rx = extract32(insn, 16, 5); 1726*98cd9ca7SRichard Henderson unsigned rb = extract32(insn, 21, 5); 1727*98cd9ca7SRichard Henderson TCGv dest; 1728*98cd9ca7SRichard Henderson 1729*98cd9ca7SRichard Henderson if (rx == 0) { 1730*98cd9ca7SRichard Henderson dest = load_gpr(ctx, rb); 1731*98cd9ca7SRichard Henderson } else { 1732*98cd9ca7SRichard Henderson dest = get_temp(ctx); 1733*98cd9ca7SRichard Henderson tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3); 1734*98cd9ca7SRichard Henderson tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb)); 1735*98cd9ca7SRichard Henderson } 1736*98cd9ca7SRichard Henderson return do_ibranch(ctx, dest, 0, n); 1737*98cd9ca7SRichard Henderson } 1738*98cd9ca7SRichard Henderson 1739*98cd9ca7SRichard Henderson static ExitStatus trans_bve(DisasContext *ctx, uint32_t insn, 1740*98cd9ca7SRichard Henderson const DisasInsn *di) 1741*98cd9ca7SRichard Henderson { 1742*98cd9ca7SRichard Henderson unsigned n = extract32(insn, 1, 1); 1743*98cd9ca7SRichard Henderson unsigned rb = extract32(insn, 21, 5); 1744*98cd9ca7SRichard Henderson unsigned link = extract32(insn, 13, 1) ? 2 : 0; 1745*98cd9ca7SRichard Henderson 1746*98cd9ca7SRichard Henderson return do_ibranch(ctx, load_gpr(ctx, rb), link, n); 1747*98cd9ca7SRichard Henderson } 1748*98cd9ca7SRichard Henderson 1749*98cd9ca7SRichard Henderson static const DisasInsn table_branch[] = { 1750*98cd9ca7SRichard Henderson { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */ 1751*98cd9ca7SRichard Henderson { 0xe800a000u, 0xfc00e000u, trans_bl_long }, 1752*98cd9ca7SRichard Henderson { 0xe8004000u, 0xfc00fffdu, trans_blr }, 1753*98cd9ca7SRichard Henderson { 0xe800c000u, 0xfc00fffdu, trans_bv }, 1754*98cd9ca7SRichard Henderson { 0xe800d000u, 0xfc00dffcu, trans_bve }, 1755*98cd9ca7SRichard Henderson }; 1756*98cd9ca7SRichard Henderson 175761766fe9SRichard Henderson static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn, 175861766fe9SRichard Henderson const DisasInsn table[], size_t n) 175961766fe9SRichard Henderson { 176061766fe9SRichard Henderson size_t i; 176161766fe9SRichard Henderson for (i = 0; i < n; ++i) { 176261766fe9SRichard Henderson if ((insn & table[i].mask) == table[i].insn) { 176361766fe9SRichard Henderson return table[i].trans(ctx, insn, &table[i]); 176461766fe9SRichard Henderson } 176561766fe9SRichard Henderson } 176661766fe9SRichard Henderson return gen_illegal(ctx); 176761766fe9SRichard Henderson } 176861766fe9SRichard Henderson 176961766fe9SRichard Henderson #define translate_table(ctx, insn, table) \ 177061766fe9SRichard Henderson translate_table_int(ctx, insn, table, ARRAY_SIZE(table)) 177161766fe9SRichard Henderson 177261766fe9SRichard Henderson static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) 177361766fe9SRichard Henderson { 177461766fe9SRichard Henderson uint32_t opc = extract32(insn, 26, 6); 177561766fe9SRichard Henderson 177661766fe9SRichard Henderson switch (opc) { 1777b2167459SRichard Henderson case 0x02: 1778b2167459SRichard Henderson return translate_table(ctx, insn, table_arith_log); 1779b2167459SRichard Henderson case 0x08: 1780b2167459SRichard Henderson return trans_ldil(ctx, insn); 1781b2167459SRichard Henderson case 0x0A: 1782b2167459SRichard Henderson return trans_addil(ctx, insn); 1783b2167459SRichard Henderson case 0x0D: 1784b2167459SRichard Henderson return trans_ldo(ctx, insn); 1785*98cd9ca7SRichard Henderson case 0x20: 1786*98cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, false, false); 1787*98cd9ca7SRichard Henderson case 0x21: 1788*98cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, true, false); 1789*98cd9ca7SRichard Henderson case 0x22: 1790*98cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, false, false); 1791*98cd9ca7SRichard Henderson case 0x23: 1792*98cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, true, false); 1793b2167459SRichard Henderson case 0x24: 1794b2167459SRichard Henderson return trans_cmpiclr(ctx, insn); 1795b2167459SRichard Henderson case 0x25: 1796b2167459SRichard Henderson return trans_subi(ctx, insn); 1797*98cd9ca7SRichard Henderson case 0x27: 1798*98cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, true, false, true); 1799*98cd9ca7SRichard Henderson case 0x28: 1800*98cd9ca7SRichard Henderson return trans_addb(ctx, insn, true, false); 1801*98cd9ca7SRichard Henderson case 0x29: 1802*98cd9ca7SRichard Henderson return trans_addb(ctx, insn, true, true); 1803*98cd9ca7SRichard Henderson case 0x2A: 1804*98cd9ca7SRichard Henderson return trans_addb(ctx, insn, false, false); 1805*98cd9ca7SRichard Henderson case 0x2B: 1806*98cd9ca7SRichard Henderson return trans_addb(ctx, insn, false, true); 1807b2167459SRichard Henderson case 0x2C: 1808b2167459SRichard Henderson case 0x2D: 1809b2167459SRichard Henderson return trans_addi(ctx, insn); 1810*98cd9ca7SRichard Henderson case 0x2F: 1811*98cd9ca7SRichard Henderson return trans_cmpb(ctx, insn, false, false, true); 1812*98cd9ca7SRichard Henderson case 0x30: 1813*98cd9ca7SRichard Henderson case 0x31: 1814*98cd9ca7SRichard Henderson return trans_bb(ctx, insn); 1815*98cd9ca7SRichard Henderson case 0x32: 1816*98cd9ca7SRichard Henderson return trans_movb(ctx, insn, false); 1817*98cd9ca7SRichard Henderson case 0x33: 1818*98cd9ca7SRichard Henderson return trans_movb(ctx, insn, true); 1819*98cd9ca7SRichard Henderson case 0x38: 1820*98cd9ca7SRichard Henderson return trans_be(ctx, insn, false); 1821*98cd9ca7SRichard Henderson case 0x39: 1822*98cd9ca7SRichard Henderson return trans_be(ctx, insn, true); 1823*98cd9ca7SRichard Henderson case 0x3A: 1824*98cd9ca7SRichard Henderson return translate_table(ctx, insn, table_branch); 182561766fe9SRichard Henderson default: 182661766fe9SRichard Henderson break; 182761766fe9SRichard Henderson } 182861766fe9SRichard Henderson return gen_illegal(ctx); 182961766fe9SRichard Henderson } 183061766fe9SRichard Henderson 183161766fe9SRichard Henderson void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb) 183261766fe9SRichard Henderson { 183361766fe9SRichard Henderson HPPACPU *cpu = hppa_env_get_cpu(env); 183461766fe9SRichard Henderson CPUState *cs = CPU(cpu); 183561766fe9SRichard Henderson DisasContext ctx; 183661766fe9SRichard Henderson ExitStatus ret; 183761766fe9SRichard Henderson int num_insns, max_insns, i; 183861766fe9SRichard Henderson 183961766fe9SRichard Henderson ctx.tb = tb; 184061766fe9SRichard Henderson ctx.cs = cs; 184161766fe9SRichard Henderson ctx.iaoq_f = tb->pc; 184261766fe9SRichard Henderson ctx.iaoq_b = tb->cs_base; 184361766fe9SRichard Henderson ctx.singlestep_enabled = cs->singlestep_enabled; 184461766fe9SRichard Henderson 184561766fe9SRichard Henderson ctx.ntemps = 0; 184661766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) { 184761766fe9SRichard Henderson TCGV_UNUSED(ctx.temps[i]); 184861766fe9SRichard Henderson } 184961766fe9SRichard Henderson 185061766fe9SRichard Henderson /* Compute the maximum number of insns to execute, as bounded by 185161766fe9SRichard Henderson (1) icount, (2) single-stepping, (3) branch delay slots, or 185261766fe9SRichard Henderson (4) the number of insns remaining on the current page. */ 185361766fe9SRichard Henderson max_insns = tb->cflags & CF_COUNT_MASK; 185461766fe9SRichard Henderson if (max_insns == 0) { 185561766fe9SRichard Henderson max_insns = CF_COUNT_MASK; 185661766fe9SRichard Henderson } 185761766fe9SRichard Henderson if (ctx.singlestep_enabled || singlestep) { 185861766fe9SRichard Henderson max_insns = 1; 185961766fe9SRichard Henderson } else if (max_insns > TCG_MAX_INSNS) { 186061766fe9SRichard Henderson max_insns = TCG_MAX_INSNS; 186161766fe9SRichard Henderson } 186261766fe9SRichard Henderson 186361766fe9SRichard Henderson num_insns = 0; 186461766fe9SRichard Henderson gen_tb_start(tb); 186561766fe9SRichard Henderson 1866129e9cc3SRichard Henderson /* Seed the nullification status from PSW[N], as shown in TB->FLAGS. */ 1867129e9cc3SRichard Henderson ctx.null_cond = cond_make_f(); 1868129e9cc3SRichard Henderson ctx.psw_n_nonzero = false; 1869129e9cc3SRichard Henderson if (tb->flags & 1) { 1870129e9cc3SRichard Henderson ctx.null_cond.c = TCG_COND_ALWAYS; 1871129e9cc3SRichard Henderson ctx.psw_n_nonzero = true; 1872129e9cc3SRichard Henderson } 1873129e9cc3SRichard Henderson ctx.null_lab = NULL; 1874129e9cc3SRichard Henderson 187561766fe9SRichard Henderson do { 187661766fe9SRichard Henderson tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b); 187761766fe9SRichard Henderson num_insns++; 187861766fe9SRichard Henderson 187961766fe9SRichard Henderson if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) { 188061766fe9SRichard Henderson ret = gen_excp(&ctx, EXCP_DEBUG); 188161766fe9SRichard Henderson break; 188261766fe9SRichard Henderson } 188361766fe9SRichard Henderson if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { 188461766fe9SRichard Henderson gen_io_start(); 188561766fe9SRichard Henderson } 188661766fe9SRichard Henderson 188761766fe9SRichard Henderson { 188861766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 188961766fe9SRichard Henderson the page permissions for execute. */ 189061766fe9SRichard Henderson uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f); 189161766fe9SRichard Henderson 189261766fe9SRichard Henderson /* Set up the IA queue for the next insn. 189361766fe9SRichard Henderson This will be overwritten by a branch. */ 189461766fe9SRichard Henderson if (ctx.iaoq_b == -1) { 189561766fe9SRichard Henderson ctx.iaoq_n = -1; 189661766fe9SRichard Henderson ctx.iaoq_n_var = get_temp(&ctx); 189761766fe9SRichard Henderson tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4); 189861766fe9SRichard Henderson } else { 189961766fe9SRichard Henderson ctx.iaoq_n = ctx.iaoq_b + 4; 190061766fe9SRichard Henderson TCGV_UNUSED(ctx.iaoq_n_var); 190161766fe9SRichard Henderson } 190261766fe9SRichard Henderson 1903129e9cc3SRichard Henderson if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) { 1904129e9cc3SRichard Henderson ctx.null_cond.c = TCG_COND_NEVER; 1905129e9cc3SRichard Henderson ret = NO_EXIT; 1906129e9cc3SRichard Henderson } else { 190761766fe9SRichard Henderson ret = translate_one(&ctx, insn); 1908129e9cc3SRichard Henderson assert(ctx.null_lab == NULL); 1909129e9cc3SRichard Henderson } 191061766fe9SRichard Henderson } 191161766fe9SRichard Henderson 191261766fe9SRichard Henderson for (i = 0; i < ctx.ntemps; ++i) { 191361766fe9SRichard Henderson tcg_temp_free(ctx.temps[i]); 191461766fe9SRichard Henderson TCGV_UNUSED(ctx.temps[i]); 191561766fe9SRichard Henderson } 191661766fe9SRichard Henderson ctx.ntemps = 0; 191761766fe9SRichard Henderson 191861766fe9SRichard Henderson /* If we see non-linear instructions, exhaust instruction count, 191961766fe9SRichard Henderson or run out of buffer space, stop generation. */ 192061766fe9SRichard Henderson /* ??? The non-linear instruction restriction is purely due to 192161766fe9SRichard Henderson the debugging dump. Otherwise we *could* follow unconditional 192261766fe9SRichard Henderson branches within the same page. */ 192361766fe9SRichard Henderson if (ret == NO_EXIT 192461766fe9SRichard Henderson && (ctx.iaoq_b != ctx.iaoq_f + 4 192561766fe9SRichard Henderson || num_insns >= max_insns 192661766fe9SRichard Henderson || tcg_op_buf_full())) { 1927129e9cc3SRichard Henderson if (ctx.null_cond.c == TCG_COND_NEVER 1928129e9cc3SRichard Henderson || ctx.null_cond.c == TCG_COND_ALWAYS) { 1929129e9cc3SRichard Henderson nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS); 1930129e9cc3SRichard Henderson gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n); 1931129e9cc3SRichard Henderson ret = EXIT_GOTO_TB; 1932129e9cc3SRichard Henderson } else { 193361766fe9SRichard Henderson ret = EXIT_IAQ_N_STALE; 193461766fe9SRichard Henderson } 1935129e9cc3SRichard Henderson } 193661766fe9SRichard Henderson 193761766fe9SRichard Henderson ctx.iaoq_f = ctx.iaoq_b; 193861766fe9SRichard Henderson ctx.iaoq_b = ctx.iaoq_n; 193961766fe9SRichard Henderson if (ret == EXIT_NORETURN 194061766fe9SRichard Henderson || ret == EXIT_GOTO_TB 194161766fe9SRichard Henderson || ret == EXIT_IAQ_N_UPDATED) { 194261766fe9SRichard Henderson break; 194361766fe9SRichard Henderson } 194461766fe9SRichard Henderson if (ctx.iaoq_f == -1) { 194561766fe9SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b); 194661766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var); 1947129e9cc3SRichard Henderson nullify_save(&ctx); 194861766fe9SRichard Henderson ret = EXIT_IAQ_N_UPDATED; 194961766fe9SRichard Henderson break; 195061766fe9SRichard Henderson } 195161766fe9SRichard Henderson if (ctx.iaoq_b == -1) { 195261766fe9SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var); 195361766fe9SRichard Henderson } 195461766fe9SRichard Henderson } while (ret == NO_EXIT); 195561766fe9SRichard Henderson 195661766fe9SRichard Henderson if (tb->cflags & CF_LAST_IO) { 195761766fe9SRichard Henderson gen_io_end(); 195861766fe9SRichard Henderson } 195961766fe9SRichard Henderson 196061766fe9SRichard Henderson switch (ret) { 196161766fe9SRichard Henderson case EXIT_GOTO_TB: 196261766fe9SRichard Henderson case EXIT_NORETURN: 196361766fe9SRichard Henderson break; 196461766fe9SRichard Henderson case EXIT_IAQ_N_STALE: 196561766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f); 196661766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b); 1967129e9cc3SRichard Henderson nullify_save(&ctx); 196861766fe9SRichard Henderson /* FALLTHRU */ 196961766fe9SRichard Henderson case EXIT_IAQ_N_UPDATED: 197061766fe9SRichard Henderson if (ctx.singlestep_enabled) { 197161766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 197261766fe9SRichard Henderson } else { 197361766fe9SRichard Henderson tcg_gen_exit_tb(0); 197461766fe9SRichard Henderson } 197561766fe9SRichard Henderson break; 197661766fe9SRichard Henderson default: 197761766fe9SRichard Henderson abort(); 197861766fe9SRichard Henderson } 197961766fe9SRichard Henderson 198061766fe9SRichard Henderson gen_tb_end(tb, num_insns); 198161766fe9SRichard Henderson 198261766fe9SRichard Henderson tb->size = num_insns * 4; 198361766fe9SRichard Henderson tb->icount = num_insns; 198461766fe9SRichard Henderson 198561766fe9SRichard Henderson #ifdef DEBUG_DISAS 198661766fe9SRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) 198761766fe9SRichard Henderson && qemu_log_in_addr_range(tb->pc)) { 198861766fe9SRichard Henderson qemu_log_lock(); 198961766fe9SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(tb->pc)); 199061766fe9SRichard Henderson log_target_disas(cs, tb->pc, tb->size, 1); 199161766fe9SRichard Henderson qemu_log("\n"); 199261766fe9SRichard Henderson qemu_log_unlock(); 199361766fe9SRichard Henderson } 199461766fe9SRichard Henderson #endif 199561766fe9SRichard Henderson } 199661766fe9SRichard Henderson 199761766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb, 199861766fe9SRichard Henderson target_ulong *data) 199961766fe9SRichard Henderson { 200061766fe9SRichard Henderson env->iaoq_f = data[0]; 200161766fe9SRichard Henderson if (data[1] != -1) { 200261766fe9SRichard Henderson env->iaoq_b = data[1]; 200361766fe9SRichard Henderson } 200461766fe9SRichard Henderson /* Since we were executing the instruction at IAOQ_F, and took some 200561766fe9SRichard Henderson sort of action that provoked the cpu_restore_state, we can infer 200661766fe9SRichard Henderson that the instruction was not nullified. */ 200761766fe9SRichard Henderson env->psw_n = 0; 200861766fe9SRichard Henderson } 2009