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); 86*b2167459SRichard Henderson union { 87*b2167459SRichard Henderson void (*f_ttt)(TCGv, TCGv, TCGv); 88*b2167459SRichard 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 449*b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign, 450*b2167459SRichard Henderson with the rest of the field becoming the least significant bits. */ 451*b2167459SRichard Henderson static target_long low_sextract(uint32_t val, int pos, int len) 452*b2167459SRichard Henderson { 453*b2167459SRichard Henderson target_ulong x = -(target_ulong)extract32(val, pos, 1); 454*b2167459SRichard Henderson x = (x << (len - 1)) | extract32(val, pos + 1, len - 1); 455*b2167459SRichard Henderson return x; 456*b2167459SRichard Henderson } 457*b2167459SRichard Henderson 458*b2167459SRichard Henderson static target_long assemble_16(uint32_t insn) 459*b2167459SRichard Henderson { 460*b2167459SRichard Henderson /* Take the name from PA2.0, which produces a 16-bit number 461*b2167459SRichard Henderson only with wide mode; otherwise a 14-bit number. Since we don't 462*b2167459SRichard Henderson implement wide mode, this is always the 14-bit number. */ 463*b2167459SRichard Henderson return low_sextract(insn, 0, 14); 464*b2167459SRichard Henderson } 465*b2167459SRichard Henderson 466*b2167459SRichard Henderson static target_long assemble_21(uint32_t insn) 467*b2167459SRichard Henderson { 468*b2167459SRichard Henderson target_ulong x = -(target_ulong)(insn & 1); 469*b2167459SRichard Henderson x = (x << 11) | extract32(insn, 1, 11); 470*b2167459SRichard Henderson x = (x << 2) | extract32(insn, 14, 2); 471*b2167459SRichard Henderson x = (x << 5) | extract32(insn, 16, 5); 472*b2167459SRichard Henderson x = (x << 2) | extract32(insn, 12, 2); 473*b2167459SRichard Henderson return x << 11; 474*b2167459SRichard Henderson } 475*b2167459SRichard Henderson 476*b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of 477*b2167459SRichard Henderson the conditions, without describing their exact implementation. The 478*b2167459SRichard Henderson interpretations do not stand up well when considering ADD,C and SUB,B. 479*b2167459SRichard Henderson However, considering the Addition, Subtraction and Logical conditions 480*b2167459SRichard Henderson as a whole it would appear that these relations are similar to what 481*b2167459SRichard Henderson a traditional NZCV set of flags would produce. */ 482*b2167459SRichard Henderson 483*b2167459SRichard Henderson static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv) 484*b2167459SRichard Henderson { 485*b2167459SRichard Henderson DisasCond cond; 486*b2167459SRichard Henderson TCGv tmp; 487*b2167459SRichard Henderson 488*b2167459SRichard Henderson switch (cf >> 1) { 489*b2167459SRichard Henderson case 0: /* Never / TR */ 490*b2167459SRichard Henderson cond = cond_make_f(); 491*b2167459SRichard Henderson break; 492*b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 493*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 494*b2167459SRichard Henderson break; 495*b2167459SRichard Henderson case 2: /* < / >= (N / !N) */ 496*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, res); 497*b2167459SRichard Henderson break; 498*b2167459SRichard Henderson case 3: /* <= / > (N | Z / !N & !Z) */ 499*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LE, res); 500*b2167459SRichard Henderson break; 501*b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 502*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 503*b2167459SRichard Henderson break; 504*b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 505*b2167459SRichard Henderson tmp = tcg_temp_new(); 506*b2167459SRichard Henderson tcg_gen_neg_tl(tmp, cb_msb); 507*b2167459SRichard Henderson tcg_gen_and_tl(tmp, tmp, res); 508*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, tmp); 509*b2167459SRichard Henderson tcg_temp_free(tmp); 510*b2167459SRichard Henderson break; 511*b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 512*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 513*b2167459SRichard Henderson break; 514*b2167459SRichard Henderson case 7: /* OD / EV */ 515*b2167459SRichard Henderson tmp = tcg_temp_new(); 516*b2167459SRichard Henderson tcg_gen_andi_tl(tmp, res, 1); 517*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 518*b2167459SRichard Henderson tcg_temp_free(tmp); 519*b2167459SRichard Henderson break; 520*b2167459SRichard Henderson default: 521*b2167459SRichard Henderson g_assert_not_reached(); 522*b2167459SRichard Henderson } 523*b2167459SRichard Henderson if (cf & 1) { 524*b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 525*b2167459SRichard Henderson } 526*b2167459SRichard Henderson 527*b2167459SRichard Henderson return cond; 528*b2167459SRichard Henderson } 529*b2167459SRichard Henderson 530*b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 531*b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 532*b2167459SRichard Henderson deleted as unused. */ 533*b2167459SRichard Henderson 534*b2167459SRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv) 535*b2167459SRichard Henderson { 536*b2167459SRichard Henderson DisasCond cond; 537*b2167459SRichard Henderson 538*b2167459SRichard Henderson switch (cf >> 1) { 539*b2167459SRichard Henderson case 1: /* = / <> */ 540*b2167459SRichard Henderson cond = cond_make(TCG_COND_EQ, in1, in2); 541*b2167459SRichard Henderson break; 542*b2167459SRichard Henderson case 2: /* < / >= */ 543*b2167459SRichard Henderson cond = cond_make(TCG_COND_LT, in1, in2); 544*b2167459SRichard Henderson break; 545*b2167459SRichard Henderson case 3: /* <= / > */ 546*b2167459SRichard Henderson cond = cond_make(TCG_COND_LE, in1, in2); 547*b2167459SRichard Henderson break; 548*b2167459SRichard Henderson case 4: /* << / >>= */ 549*b2167459SRichard Henderson cond = cond_make(TCG_COND_LTU, in1, in2); 550*b2167459SRichard Henderson break; 551*b2167459SRichard Henderson case 5: /* <<= / >> */ 552*b2167459SRichard Henderson cond = cond_make(TCG_COND_LEU, in1, in2); 553*b2167459SRichard Henderson break; 554*b2167459SRichard Henderson default: 555*b2167459SRichard Henderson return do_cond(cf, res, sv, sv); 556*b2167459SRichard Henderson } 557*b2167459SRichard Henderson if (cf & 1) { 558*b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 559*b2167459SRichard Henderson } 560*b2167459SRichard Henderson 561*b2167459SRichard Henderson return cond; 562*b2167459SRichard Henderson } 563*b2167459SRichard Henderson 564*b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not 565*b2167459SRichard Henderson computed, and use of them is undefined. */ 566*b2167459SRichard Henderson 567*b2167459SRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv res) 568*b2167459SRichard Henderson { 569*b2167459SRichard Henderson switch (cf >> 1) { 570*b2167459SRichard Henderson case 4: case 5: case 6: 571*b2167459SRichard Henderson cf &= 1; 572*b2167459SRichard Henderson break; 573*b2167459SRichard Henderson } 574*b2167459SRichard Henderson return do_cond(cf, res, res, res); 575*b2167459SRichard Henderson } 576*b2167459SRichard Henderson 577*b2167459SRichard Henderson /* Similar, but for unit conditions. */ 578*b2167459SRichard Henderson 579*b2167459SRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2) 580*b2167459SRichard Henderson { 581*b2167459SRichard Henderson DisasCond cond; 582*b2167459SRichard Henderson TCGv tmp, cb; 583*b2167459SRichard Henderson 584*b2167459SRichard Henderson TCGV_UNUSED(cb); 585*b2167459SRichard Henderson if (cf & 8) { 586*b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 587*b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 588*b2167459SRichard Henderson * leaves us with carry bits spread across two words. 589*b2167459SRichard Henderson */ 590*b2167459SRichard Henderson cb = tcg_temp_new(); 591*b2167459SRichard Henderson tmp = tcg_temp_new(); 592*b2167459SRichard Henderson tcg_gen_or_tl(cb, in1, in2); 593*b2167459SRichard Henderson tcg_gen_and_tl(tmp, in1, in2); 594*b2167459SRichard Henderson tcg_gen_andc_tl(cb, cb, res); 595*b2167459SRichard Henderson tcg_gen_or_tl(cb, cb, tmp); 596*b2167459SRichard Henderson tcg_temp_free(tmp); 597*b2167459SRichard Henderson } 598*b2167459SRichard Henderson 599*b2167459SRichard Henderson switch (cf >> 1) { 600*b2167459SRichard Henderson case 0: /* never / TR */ 601*b2167459SRichard Henderson case 1: /* undefined */ 602*b2167459SRichard Henderson case 5: /* undefined */ 603*b2167459SRichard Henderson cond = cond_make_f(); 604*b2167459SRichard Henderson break; 605*b2167459SRichard Henderson 606*b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 607*b2167459SRichard Henderson /* See hasless(v,1) from 608*b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 609*b2167459SRichard Henderson */ 610*b2167459SRichard Henderson tmp = tcg_temp_new(); 611*b2167459SRichard Henderson tcg_gen_subi_tl(tmp, res, 0x01010101u); 612*b2167459SRichard Henderson tcg_gen_andc_tl(tmp, tmp, res); 613*b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x80808080u); 614*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 615*b2167459SRichard Henderson tcg_temp_free(tmp); 616*b2167459SRichard Henderson break; 617*b2167459SRichard Henderson 618*b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 619*b2167459SRichard Henderson tmp = tcg_temp_new(); 620*b2167459SRichard Henderson tcg_gen_subi_tl(tmp, res, 0x00010001u); 621*b2167459SRichard Henderson tcg_gen_andc_tl(tmp, tmp, res); 622*b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x80008000u); 623*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 624*b2167459SRichard Henderson tcg_temp_free(tmp); 625*b2167459SRichard Henderson break; 626*b2167459SRichard Henderson 627*b2167459SRichard Henderson case 4: /* SDC / NDC */ 628*b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x88888888u); 629*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 630*b2167459SRichard Henderson break; 631*b2167459SRichard Henderson 632*b2167459SRichard Henderson case 6: /* SBC / NBC */ 633*b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x80808080u); 634*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 635*b2167459SRichard Henderson break; 636*b2167459SRichard Henderson 637*b2167459SRichard Henderson case 7: /* SHC / NHC */ 638*b2167459SRichard Henderson tcg_gen_andi_tl(cb, cb, 0x80008000u); 639*b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 640*b2167459SRichard Henderson break; 641*b2167459SRichard Henderson 642*b2167459SRichard Henderson default: 643*b2167459SRichard Henderson g_assert_not_reached(); 644*b2167459SRichard Henderson } 645*b2167459SRichard Henderson if (cf & 8) { 646*b2167459SRichard Henderson tcg_temp_free(cb); 647*b2167459SRichard Henderson } 648*b2167459SRichard Henderson if (cf & 1) { 649*b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 650*b2167459SRichard Henderson } 651*b2167459SRichard Henderson 652*b2167459SRichard Henderson return cond; 653*b2167459SRichard Henderson } 654*b2167459SRichard Henderson 655*b2167459SRichard Henderson /* Compute signed overflow for addition. */ 656*b2167459SRichard Henderson static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2) 657*b2167459SRichard Henderson { 658*b2167459SRichard Henderson TCGv sv = get_temp(ctx); 659*b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 660*b2167459SRichard Henderson 661*b2167459SRichard Henderson tcg_gen_xor_tl(sv, res, in1); 662*b2167459SRichard Henderson tcg_gen_xor_tl(tmp, in1, in2); 663*b2167459SRichard Henderson tcg_gen_andc_tl(sv, sv, tmp); 664*b2167459SRichard Henderson tcg_temp_free(tmp); 665*b2167459SRichard Henderson 666*b2167459SRichard Henderson return sv; 667*b2167459SRichard Henderson } 668*b2167459SRichard Henderson 669*b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 670*b2167459SRichard Henderson static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2) 671*b2167459SRichard Henderson { 672*b2167459SRichard Henderson TCGv sv = get_temp(ctx); 673*b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 674*b2167459SRichard Henderson 675*b2167459SRichard Henderson tcg_gen_xor_tl(sv, res, in1); 676*b2167459SRichard Henderson tcg_gen_xor_tl(tmp, in1, in2); 677*b2167459SRichard Henderson tcg_gen_and_tl(sv, sv, tmp); 678*b2167459SRichard Henderson tcg_temp_free(tmp); 679*b2167459SRichard Henderson 680*b2167459SRichard Henderson return sv; 681*b2167459SRichard Henderson } 682*b2167459SRichard Henderson 683*b2167459SRichard Henderson static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 684*b2167459SRichard Henderson unsigned shift, bool is_l, bool is_tsv, bool is_tc, 685*b2167459SRichard Henderson bool is_c, unsigned cf) 686*b2167459SRichard Henderson { 687*b2167459SRichard Henderson TCGv dest, cb, cb_msb, sv, tmp; 688*b2167459SRichard Henderson unsigned c = cf >> 1; 689*b2167459SRichard Henderson DisasCond cond; 690*b2167459SRichard Henderson 691*b2167459SRichard Henderson dest = tcg_temp_new(); 692*b2167459SRichard Henderson TCGV_UNUSED(cb); 693*b2167459SRichard Henderson TCGV_UNUSED(cb_msb); 694*b2167459SRichard Henderson 695*b2167459SRichard Henderson if (shift) { 696*b2167459SRichard Henderson tmp = get_temp(ctx); 697*b2167459SRichard Henderson tcg_gen_shli_tl(tmp, in1, shift); 698*b2167459SRichard Henderson in1 = tmp; 699*b2167459SRichard Henderson } 700*b2167459SRichard Henderson 701*b2167459SRichard Henderson if (!is_l || c == 4 || c == 5) { 702*b2167459SRichard Henderson TCGv zero = tcg_const_tl(0); 703*b2167459SRichard Henderson cb_msb = get_temp(ctx); 704*b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero); 705*b2167459SRichard Henderson if (is_c) { 706*b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero); 707*b2167459SRichard Henderson } 708*b2167459SRichard Henderson tcg_temp_free(zero); 709*b2167459SRichard Henderson if (!is_l) { 710*b2167459SRichard Henderson cb = get_temp(ctx); 711*b2167459SRichard Henderson tcg_gen_xor_tl(cb, in1, in2); 712*b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 713*b2167459SRichard Henderson } 714*b2167459SRichard Henderson } else { 715*b2167459SRichard Henderson tcg_gen_add_tl(dest, in1, in2); 716*b2167459SRichard Henderson if (is_c) { 717*b2167459SRichard Henderson tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb); 718*b2167459SRichard Henderson } 719*b2167459SRichard Henderson } 720*b2167459SRichard Henderson 721*b2167459SRichard Henderson /* Compute signed overflow if required. */ 722*b2167459SRichard Henderson TCGV_UNUSED(sv); 723*b2167459SRichard Henderson if (is_tsv || c == 6) { 724*b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 725*b2167459SRichard Henderson if (is_tsv) { 726*b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 727*b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 728*b2167459SRichard Henderson } 729*b2167459SRichard Henderson } 730*b2167459SRichard Henderson 731*b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 732*b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 733*b2167459SRichard Henderson if (is_tc) { 734*b2167459SRichard Henderson cond_prep(&cond); 735*b2167459SRichard Henderson tmp = tcg_temp_new(); 736*b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 737*b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 738*b2167459SRichard Henderson tcg_temp_free(tmp); 739*b2167459SRichard Henderson } 740*b2167459SRichard Henderson 741*b2167459SRichard Henderson /* Write back the result. */ 742*b2167459SRichard Henderson if (!is_l) { 743*b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 744*b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 745*b2167459SRichard Henderson } 746*b2167459SRichard Henderson save_gpr(ctx, rt, dest); 747*b2167459SRichard Henderson tcg_temp_free(dest); 748*b2167459SRichard Henderson 749*b2167459SRichard Henderson /* Install the new nullification. */ 750*b2167459SRichard Henderson cond_free(&ctx->null_cond); 751*b2167459SRichard Henderson ctx->null_cond = cond; 752*b2167459SRichard Henderson return NO_EXIT; 753*b2167459SRichard Henderson } 754*b2167459SRichard Henderson 755*b2167459SRichard Henderson static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 756*b2167459SRichard Henderson bool is_tsv, bool is_b, bool is_tc, unsigned cf) 757*b2167459SRichard Henderson { 758*b2167459SRichard Henderson TCGv dest, sv, cb, cb_msb, zero, tmp; 759*b2167459SRichard Henderson unsigned c = cf >> 1; 760*b2167459SRichard Henderson DisasCond cond; 761*b2167459SRichard Henderson 762*b2167459SRichard Henderson dest = tcg_temp_new(); 763*b2167459SRichard Henderson cb = tcg_temp_new(); 764*b2167459SRichard Henderson cb_msb = tcg_temp_new(); 765*b2167459SRichard Henderson 766*b2167459SRichard Henderson zero = tcg_const_tl(0); 767*b2167459SRichard Henderson if (is_b) { 768*b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 769*b2167459SRichard Henderson tcg_gen_not_tl(cb, in2); 770*b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero); 771*b2167459SRichard Henderson tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero); 772*b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, in1); 773*b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 774*b2167459SRichard Henderson } else { 775*b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 776*b2167459SRichard Henderson operations by seeding the high word with 1 and subtracting. */ 777*b2167459SRichard Henderson tcg_gen_movi_tl(cb_msb, 1); 778*b2167459SRichard Henderson tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero); 779*b2167459SRichard Henderson tcg_gen_eqv_tl(cb, in1, in2); 780*b2167459SRichard Henderson tcg_gen_xor_tl(cb, cb, dest); 781*b2167459SRichard Henderson } 782*b2167459SRichard Henderson tcg_temp_free(zero); 783*b2167459SRichard Henderson 784*b2167459SRichard Henderson /* Compute signed overflow if required. */ 785*b2167459SRichard Henderson TCGV_UNUSED(sv); 786*b2167459SRichard Henderson if (is_tsv || c == 6) { 787*b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 788*b2167459SRichard Henderson if (is_tsv) { 789*b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 790*b2167459SRichard Henderson } 791*b2167459SRichard Henderson } 792*b2167459SRichard Henderson 793*b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 794*b2167459SRichard Henderson if (!is_b) { 795*b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 796*b2167459SRichard Henderson } else { 797*b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 798*b2167459SRichard Henderson } 799*b2167459SRichard Henderson 800*b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 801*b2167459SRichard Henderson if (is_tc) { 802*b2167459SRichard Henderson cond_prep(&cond); 803*b2167459SRichard Henderson tmp = tcg_temp_new(); 804*b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 805*b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 806*b2167459SRichard Henderson tcg_temp_free(tmp); 807*b2167459SRichard Henderson } 808*b2167459SRichard Henderson 809*b2167459SRichard Henderson /* Write back the result. */ 810*b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 811*b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 812*b2167459SRichard Henderson save_gpr(ctx, rt, dest); 813*b2167459SRichard Henderson tcg_temp_free(dest); 814*b2167459SRichard Henderson 815*b2167459SRichard Henderson /* Install the new nullification. */ 816*b2167459SRichard Henderson cond_free(&ctx->null_cond); 817*b2167459SRichard Henderson ctx->null_cond = cond; 818*b2167459SRichard Henderson return NO_EXIT; 819*b2167459SRichard Henderson } 820*b2167459SRichard Henderson 821*b2167459SRichard Henderson static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1, 822*b2167459SRichard Henderson TCGv in2, unsigned cf) 823*b2167459SRichard Henderson { 824*b2167459SRichard Henderson TCGv dest, sv; 825*b2167459SRichard Henderson DisasCond cond; 826*b2167459SRichard Henderson 827*b2167459SRichard Henderson dest = tcg_temp_new(); 828*b2167459SRichard Henderson tcg_gen_sub_tl(dest, in1, in2); 829*b2167459SRichard Henderson 830*b2167459SRichard Henderson /* Compute signed overflow if required. */ 831*b2167459SRichard Henderson TCGV_UNUSED(sv); 832*b2167459SRichard Henderson if ((cf >> 1) == 6) { 833*b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 834*b2167459SRichard Henderson } 835*b2167459SRichard Henderson 836*b2167459SRichard Henderson /* Form the condition for the compare. */ 837*b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 838*b2167459SRichard Henderson 839*b2167459SRichard Henderson /* Clear. */ 840*b2167459SRichard Henderson tcg_gen_movi_tl(dest, 0); 841*b2167459SRichard Henderson save_gpr(ctx, rt, dest); 842*b2167459SRichard Henderson tcg_temp_free(dest); 843*b2167459SRichard Henderson 844*b2167459SRichard Henderson /* Install the new nullification. */ 845*b2167459SRichard Henderson cond_free(&ctx->null_cond); 846*b2167459SRichard Henderson ctx->null_cond = cond; 847*b2167459SRichard Henderson return NO_EXIT; 848*b2167459SRichard Henderson } 849*b2167459SRichard Henderson 850*b2167459SRichard Henderson static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, 851*b2167459SRichard Henderson unsigned cf, void (*fn)(TCGv, TCGv, TCGv)) 852*b2167459SRichard Henderson { 853*b2167459SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 854*b2167459SRichard Henderson 855*b2167459SRichard Henderson /* Perform the operation, and writeback. */ 856*b2167459SRichard Henderson fn(dest, in1, in2); 857*b2167459SRichard Henderson save_gpr(ctx, rt, dest); 858*b2167459SRichard Henderson 859*b2167459SRichard Henderson /* Install the new nullification. */ 860*b2167459SRichard Henderson cond_free(&ctx->null_cond); 861*b2167459SRichard Henderson if (cf) { 862*b2167459SRichard Henderson ctx->null_cond = do_log_cond(cf, dest); 863*b2167459SRichard Henderson } 864*b2167459SRichard Henderson return NO_EXIT; 865*b2167459SRichard Henderson } 866*b2167459SRichard Henderson 867*b2167459SRichard Henderson static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1, 868*b2167459SRichard Henderson TCGv in2, unsigned cf, bool is_tc, 869*b2167459SRichard Henderson void (*fn)(TCGv, TCGv, TCGv)) 870*b2167459SRichard Henderson { 871*b2167459SRichard Henderson TCGv dest; 872*b2167459SRichard Henderson DisasCond cond; 873*b2167459SRichard Henderson 874*b2167459SRichard Henderson if (cf == 0) { 875*b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 876*b2167459SRichard Henderson fn(dest, in1, in2); 877*b2167459SRichard Henderson save_gpr(ctx, rt, dest); 878*b2167459SRichard Henderson cond_free(&ctx->null_cond); 879*b2167459SRichard Henderson } else { 880*b2167459SRichard Henderson dest = tcg_temp_new(); 881*b2167459SRichard Henderson fn(dest, in1, in2); 882*b2167459SRichard Henderson 883*b2167459SRichard Henderson cond = do_unit_cond(cf, dest, in1, in2); 884*b2167459SRichard Henderson 885*b2167459SRichard Henderson if (is_tc) { 886*b2167459SRichard Henderson TCGv tmp = tcg_temp_new(); 887*b2167459SRichard Henderson cond_prep(&cond); 888*b2167459SRichard Henderson tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1); 889*b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 890*b2167459SRichard Henderson tcg_temp_free(tmp); 891*b2167459SRichard Henderson } 892*b2167459SRichard Henderson save_gpr(ctx, rt, dest); 893*b2167459SRichard Henderson 894*b2167459SRichard Henderson cond_free(&ctx->null_cond); 895*b2167459SRichard Henderson ctx->null_cond = cond; 896*b2167459SRichard Henderson } 897*b2167459SRichard Henderson return NO_EXIT; 898*b2167459SRichard Henderson } 899*b2167459SRichard Henderson 900*b2167459SRichard Henderson static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn, 901*b2167459SRichard Henderson const DisasInsn *di) 902*b2167459SRichard Henderson { 903*b2167459SRichard Henderson cond_free(&ctx->null_cond); 904*b2167459SRichard Henderson return NO_EXIT; 905*b2167459SRichard Henderson } 906*b2167459SRichard Henderson 907*b2167459SRichard Henderson static ExitStatus trans_add(DisasContext *ctx, uint32_t insn, 908*b2167459SRichard Henderson const DisasInsn *di) 909*b2167459SRichard Henderson { 910*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 911*b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 912*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 913*b2167459SRichard Henderson unsigned ext = extract32(insn, 8, 4); 914*b2167459SRichard Henderson unsigned shift = extract32(insn, 6, 2); 915*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 916*b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 917*b2167459SRichard Henderson bool is_c = false; 918*b2167459SRichard Henderson bool is_l = false; 919*b2167459SRichard Henderson bool is_tc = false; 920*b2167459SRichard Henderson bool is_tsv = false; 921*b2167459SRichard Henderson ExitStatus ret; 922*b2167459SRichard Henderson 923*b2167459SRichard Henderson switch (ext) { 924*b2167459SRichard Henderson case 0x6: /* ADD, SHLADD */ 925*b2167459SRichard Henderson break; 926*b2167459SRichard Henderson case 0xa: /* ADD,L, SHLADD,L */ 927*b2167459SRichard Henderson is_l = true; 928*b2167459SRichard Henderson break; 929*b2167459SRichard Henderson case 0xe: /* ADD,TSV, SHLADD,TSV (1) */ 930*b2167459SRichard Henderson is_tsv = true; 931*b2167459SRichard Henderson break; 932*b2167459SRichard Henderson case 0x7: /* ADD,C */ 933*b2167459SRichard Henderson is_c = true; 934*b2167459SRichard Henderson break; 935*b2167459SRichard Henderson case 0xf: /* ADD,C,TSV */ 936*b2167459SRichard Henderson is_c = is_tsv = true; 937*b2167459SRichard Henderson break; 938*b2167459SRichard Henderson default: 939*b2167459SRichard Henderson return gen_illegal(ctx); 940*b2167459SRichard Henderson } 941*b2167459SRichard Henderson 942*b2167459SRichard Henderson if (cf) { 943*b2167459SRichard Henderson nullify_over(ctx); 944*b2167459SRichard Henderson } 945*b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 946*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 947*b2167459SRichard Henderson ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf); 948*b2167459SRichard Henderson return nullify_end(ctx, ret); 949*b2167459SRichard Henderson } 950*b2167459SRichard Henderson 951*b2167459SRichard Henderson static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn, 952*b2167459SRichard Henderson const DisasInsn *di) 953*b2167459SRichard Henderson { 954*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 955*b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 956*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 957*b2167459SRichard Henderson unsigned ext = extract32(insn, 6, 6); 958*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 959*b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 960*b2167459SRichard Henderson bool is_b = false; 961*b2167459SRichard Henderson bool is_tc = false; 962*b2167459SRichard Henderson bool is_tsv = false; 963*b2167459SRichard Henderson ExitStatus ret; 964*b2167459SRichard Henderson 965*b2167459SRichard Henderson switch (ext) { 966*b2167459SRichard Henderson case 0x10: /* SUB */ 967*b2167459SRichard Henderson break; 968*b2167459SRichard Henderson case 0x30: /* SUB,TSV */ 969*b2167459SRichard Henderson is_tsv = true; 970*b2167459SRichard Henderson break; 971*b2167459SRichard Henderson case 0x14: /* SUB,B */ 972*b2167459SRichard Henderson is_b = true; 973*b2167459SRichard Henderson break; 974*b2167459SRichard Henderson case 0x34: /* SUB,B,TSV */ 975*b2167459SRichard Henderson is_b = is_tsv = true; 976*b2167459SRichard Henderson break; 977*b2167459SRichard Henderson case 0x13: /* SUB,TC */ 978*b2167459SRichard Henderson is_tc = true; 979*b2167459SRichard Henderson break; 980*b2167459SRichard Henderson case 0x33: /* SUB,TSV,TC */ 981*b2167459SRichard Henderson is_tc = is_tsv = true; 982*b2167459SRichard Henderson break; 983*b2167459SRichard Henderson default: 984*b2167459SRichard Henderson return gen_illegal(ctx); 985*b2167459SRichard Henderson } 986*b2167459SRichard Henderson 987*b2167459SRichard Henderson if (cf) { 988*b2167459SRichard Henderson nullify_over(ctx); 989*b2167459SRichard Henderson } 990*b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 991*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 992*b2167459SRichard Henderson ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf); 993*b2167459SRichard Henderson return nullify_end(ctx, ret); 994*b2167459SRichard Henderson } 995*b2167459SRichard Henderson 996*b2167459SRichard Henderson static ExitStatus trans_log(DisasContext *ctx, uint32_t insn, 997*b2167459SRichard Henderson const DisasInsn *di) 998*b2167459SRichard Henderson { 999*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1000*b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1001*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1002*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1003*b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1004*b2167459SRichard Henderson ExitStatus ret; 1005*b2167459SRichard Henderson 1006*b2167459SRichard Henderson if (cf) { 1007*b2167459SRichard Henderson nullify_over(ctx); 1008*b2167459SRichard Henderson } 1009*b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1010*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1011*b2167459SRichard Henderson ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f_ttt); 1012*b2167459SRichard Henderson return nullify_end(ctx, ret); 1013*b2167459SRichard Henderson } 1014*b2167459SRichard Henderson 1015*b2167459SRichard Henderson /* OR r,0,t -> COPY (according to gas) */ 1016*b2167459SRichard Henderson static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn, 1017*b2167459SRichard Henderson const DisasInsn *di) 1018*b2167459SRichard Henderson { 1019*b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1020*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1021*b2167459SRichard Henderson 1022*b2167459SRichard Henderson if (r1 == 0) { 1023*b2167459SRichard Henderson TCGv dest = dest_gpr(ctx, rt); 1024*b2167459SRichard Henderson tcg_gen_movi_tl(dest, 0); 1025*b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1026*b2167459SRichard Henderson } else { 1027*b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 1028*b2167459SRichard Henderson } 1029*b2167459SRichard Henderson cond_free(&ctx->null_cond); 1030*b2167459SRichard Henderson return NO_EXIT; 1031*b2167459SRichard Henderson } 1032*b2167459SRichard Henderson 1033*b2167459SRichard Henderson static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn, 1034*b2167459SRichard Henderson const DisasInsn *di) 1035*b2167459SRichard Henderson { 1036*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1037*b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1038*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1039*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1040*b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1041*b2167459SRichard Henderson ExitStatus ret; 1042*b2167459SRichard Henderson 1043*b2167459SRichard Henderson if (cf) { 1044*b2167459SRichard Henderson nullify_over(ctx); 1045*b2167459SRichard Henderson } 1046*b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1047*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1048*b2167459SRichard Henderson ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf); 1049*b2167459SRichard Henderson return nullify_end(ctx, ret); 1050*b2167459SRichard Henderson } 1051*b2167459SRichard Henderson 1052*b2167459SRichard Henderson static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn, 1053*b2167459SRichard Henderson const DisasInsn *di) 1054*b2167459SRichard Henderson { 1055*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1056*b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1057*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1058*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1059*b2167459SRichard Henderson TCGv tcg_r1, tcg_r2; 1060*b2167459SRichard Henderson ExitStatus ret; 1061*b2167459SRichard Henderson 1062*b2167459SRichard Henderson if (cf) { 1063*b2167459SRichard Henderson nullify_over(ctx); 1064*b2167459SRichard Henderson } 1065*b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1066*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1067*b2167459SRichard Henderson ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl); 1068*b2167459SRichard Henderson return nullify_end(ctx, ret); 1069*b2167459SRichard Henderson } 1070*b2167459SRichard Henderson 1071*b2167459SRichard Henderson static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn, 1072*b2167459SRichard Henderson const DisasInsn *di) 1073*b2167459SRichard Henderson { 1074*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1075*b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1076*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1077*b2167459SRichard Henderson unsigned is_tc = extract32(insn, 6, 1); 1078*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1079*b2167459SRichard Henderson TCGv tcg_r1, tcg_r2, tmp; 1080*b2167459SRichard Henderson ExitStatus ret; 1081*b2167459SRichard Henderson 1082*b2167459SRichard Henderson if (cf) { 1083*b2167459SRichard Henderson nullify_over(ctx); 1084*b2167459SRichard Henderson } 1085*b2167459SRichard Henderson tcg_r1 = load_gpr(ctx, r1); 1086*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1087*b2167459SRichard Henderson tmp = get_temp(ctx); 1088*b2167459SRichard Henderson tcg_gen_not_tl(tmp, tcg_r2); 1089*b2167459SRichard Henderson ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl); 1090*b2167459SRichard Henderson return nullify_end(ctx, ret); 1091*b2167459SRichard Henderson } 1092*b2167459SRichard Henderson 1093*b2167459SRichard Henderson static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn, 1094*b2167459SRichard Henderson const DisasInsn *di) 1095*b2167459SRichard Henderson { 1096*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1097*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1098*b2167459SRichard Henderson unsigned is_i = extract32(insn, 6, 1); 1099*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1100*b2167459SRichard Henderson TCGv tmp; 1101*b2167459SRichard Henderson ExitStatus ret; 1102*b2167459SRichard Henderson 1103*b2167459SRichard Henderson nullify_over(ctx); 1104*b2167459SRichard Henderson 1105*b2167459SRichard Henderson tmp = get_temp(ctx); 1106*b2167459SRichard Henderson tcg_gen_shri_tl(tmp, cpu_psw_cb, 3); 1107*b2167459SRichard Henderson if (!is_i) { 1108*b2167459SRichard Henderson tcg_gen_not_tl(tmp, tmp); 1109*b2167459SRichard Henderson } 1110*b2167459SRichard Henderson tcg_gen_andi_tl(tmp, tmp, 0x11111111); 1111*b2167459SRichard Henderson tcg_gen_muli_tl(tmp, tmp, 6); 1112*b2167459SRichard Henderson ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false, 1113*b2167459SRichard Henderson is_i ? tcg_gen_add_tl : tcg_gen_sub_tl); 1114*b2167459SRichard Henderson 1115*b2167459SRichard Henderson return nullify_end(ctx, ret); 1116*b2167459SRichard Henderson } 1117*b2167459SRichard Henderson 1118*b2167459SRichard Henderson static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn, 1119*b2167459SRichard Henderson const DisasInsn *di) 1120*b2167459SRichard Henderson { 1121*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1122*b2167459SRichard Henderson unsigned r1 = extract32(insn, 16, 5); 1123*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1124*b2167459SRichard Henderson unsigned rt = extract32(insn, 0, 5); 1125*b2167459SRichard Henderson TCGv dest, add1, add2, addc, zero, in1, in2; 1126*b2167459SRichard Henderson 1127*b2167459SRichard Henderson nullify_over(ctx); 1128*b2167459SRichard Henderson 1129*b2167459SRichard Henderson in1 = load_gpr(ctx, r1); 1130*b2167459SRichard Henderson in2 = load_gpr(ctx, r2); 1131*b2167459SRichard Henderson 1132*b2167459SRichard Henderson add1 = tcg_temp_new(); 1133*b2167459SRichard Henderson add2 = tcg_temp_new(); 1134*b2167459SRichard Henderson addc = tcg_temp_new(); 1135*b2167459SRichard Henderson dest = tcg_temp_new(); 1136*b2167459SRichard Henderson zero = tcg_const_tl(0); 1137*b2167459SRichard Henderson 1138*b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 1139*b2167459SRichard Henderson tcg_gen_add_tl(add1, in1, in1); 1140*b2167459SRichard Henderson tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb); 1141*b2167459SRichard Henderson 1142*b2167459SRichard Henderson /* Add or subtract R2, depending on PSW[V]. Proper computation of 1143*b2167459SRichard Henderson carry{8} requires that we subtract via + ~R2 + 1, as described in 1144*b2167459SRichard Henderson the manual. By extracting and masking V, we can produce the 1145*b2167459SRichard Henderson proper inputs to the addition without movcond. */ 1146*b2167459SRichard Henderson tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1); 1147*b2167459SRichard Henderson tcg_gen_xor_tl(add2, in2, addc); 1148*b2167459SRichard Henderson tcg_gen_andi_tl(addc, addc, 1); 1149*b2167459SRichard Henderson /* ??? This is only correct for 32-bit. */ 1150*b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero); 1151*b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero); 1152*b2167459SRichard Henderson 1153*b2167459SRichard Henderson tcg_temp_free(addc); 1154*b2167459SRichard Henderson tcg_temp_free(zero); 1155*b2167459SRichard Henderson 1156*b2167459SRichard Henderson /* Write back the result register. */ 1157*b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1158*b2167459SRichard Henderson 1159*b2167459SRichard Henderson /* Write back PSW[CB]. */ 1160*b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_cb, add1, add2); 1161*b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest); 1162*b2167459SRichard Henderson 1163*b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 1164*b2167459SRichard Henderson tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb); 1165*b2167459SRichard Henderson tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2); 1166*b2167459SRichard Henderson 1167*b2167459SRichard Henderson /* Install the new nullification. */ 1168*b2167459SRichard Henderson if (cf) { 1169*b2167459SRichard Henderson TCGv sv; 1170*b2167459SRichard Henderson TCGV_UNUSED(sv); 1171*b2167459SRichard Henderson if (cf >> 1 == 6) { 1172*b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 1173*b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 1174*b2167459SRichard Henderson } 1175*b2167459SRichard Henderson ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv); 1176*b2167459SRichard Henderson } 1177*b2167459SRichard Henderson 1178*b2167459SRichard Henderson tcg_temp_free(add1); 1179*b2167459SRichard Henderson tcg_temp_free(add2); 1180*b2167459SRichard Henderson tcg_temp_free(dest); 1181*b2167459SRichard Henderson 1182*b2167459SRichard Henderson return nullify_end(ctx, NO_EXIT); 1183*b2167459SRichard Henderson } 1184*b2167459SRichard Henderson 1185*b2167459SRichard Henderson static const DisasInsn table_arith_log[] = { 1186*b2167459SRichard Henderson { 0x08000240u, 0xfc00ffffu, trans_nop }, /* or x,y,0 */ 1187*b2167459SRichard Henderson { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */ 1188*b2167459SRichard Henderson { 0x08000000u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_andc_tl }, 1189*b2167459SRichard Henderson { 0x08000200u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_and_tl }, 1190*b2167459SRichard Henderson { 0x08000240u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_or_tl }, 1191*b2167459SRichard Henderson { 0x08000280u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_xor_tl }, 1192*b2167459SRichard Henderson { 0x08000880u, 0xfc000fe0u, trans_cmpclr }, 1193*b2167459SRichard Henderson { 0x08000380u, 0xfc000fe0u, trans_uxor }, 1194*b2167459SRichard Henderson { 0x08000980u, 0xfc000fa0u, trans_uaddcm }, 1195*b2167459SRichard Henderson { 0x08000b80u, 0xfc1f0fa0u, trans_dcor }, 1196*b2167459SRichard Henderson { 0x08000440u, 0xfc000fe0u, trans_ds }, 1197*b2167459SRichard Henderson { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */ 1198*b2167459SRichard Henderson { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */ 1199*b2167459SRichard Henderson { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */ 1200*b2167459SRichard Henderson { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */ 1201*b2167459SRichard Henderson }; 1202*b2167459SRichard Henderson 1203*b2167459SRichard Henderson static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn) 1204*b2167459SRichard Henderson { 1205*b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1206*b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 1207*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1208*b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1209*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1210*b2167459SRichard Henderson unsigned o1 = extract32(insn, 26, 1); 1211*b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1212*b2167459SRichard Henderson ExitStatus ret; 1213*b2167459SRichard Henderson 1214*b2167459SRichard Henderson if (cf) { 1215*b2167459SRichard Henderson nullify_over(ctx); 1216*b2167459SRichard Henderson } 1217*b2167459SRichard Henderson 1218*b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1219*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1220*b2167459SRichard Henderson ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf); 1221*b2167459SRichard Henderson 1222*b2167459SRichard Henderson return nullify_end(ctx, ret); 1223*b2167459SRichard Henderson } 1224*b2167459SRichard Henderson 1225*b2167459SRichard Henderson static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn) 1226*b2167459SRichard Henderson { 1227*b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1228*b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 1229*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1230*b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1231*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1232*b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1233*b2167459SRichard Henderson ExitStatus ret; 1234*b2167459SRichard Henderson 1235*b2167459SRichard Henderson if (cf) { 1236*b2167459SRichard Henderson nullify_over(ctx); 1237*b2167459SRichard Henderson } 1238*b2167459SRichard Henderson 1239*b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1240*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1241*b2167459SRichard Henderson ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf); 1242*b2167459SRichard Henderson 1243*b2167459SRichard Henderson return nullify_end(ctx, ret); 1244*b2167459SRichard Henderson } 1245*b2167459SRichard Henderson 1246*b2167459SRichard Henderson static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn) 1247*b2167459SRichard Henderson { 1248*b2167459SRichard Henderson target_long im = low_sextract(insn, 0, 11); 1249*b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 1250*b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1251*b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 1252*b2167459SRichard Henderson TCGv tcg_im, tcg_r2; 1253*b2167459SRichard Henderson ExitStatus ret; 1254*b2167459SRichard Henderson 1255*b2167459SRichard Henderson if (cf) { 1256*b2167459SRichard Henderson nullify_over(ctx); 1257*b2167459SRichard Henderson } 1258*b2167459SRichard Henderson 1259*b2167459SRichard Henderson tcg_im = load_const(ctx, im); 1260*b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 1261*b2167459SRichard Henderson ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf); 1262*b2167459SRichard Henderson 1263*b2167459SRichard Henderson return nullify_end(ctx, ret); 1264*b2167459SRichard Henderson } 1265*b2167459SRichard Henderson 1266*b2167459SRichard Henderson static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn) 1267*b2167459SRichard Henderson { 1268*b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 1269*b2167459SRichard Henderson target_long i = assemble_21(insn); 1270*b2167459SRichard Henderson TCGv tcg_rt = dest_gpr(ctx, rt); 1271*b2167459SRichard Henderson 1272*b2167459SRichard Henderson tcg_gen_movi_tl(tcg_rt, i); 1273*b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 1274*b2167459SRichard Henderson cond_free(&ctx->null_cond); 1275*b2167459SRichard Henderson 1276*b2167459SRichard Henderson return NO_EXIT; 1277*b2167459SRichard Henderson } 1278*b2167459SRichard Henderson 1279*b2167459SRichard Henderson static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn) 1280*b2167459SRichard Henderson { 1281*b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 1282*b2167459SRichard Henderson target_long i = assemble_21(insn); 1283*b2167459SRichard Henderson TCGv tcg_rt = load_gpr(ctx, rt); 1284*b2167459SRichard Henderson TCGv tcg_r1 = dest_gpr(ctx, 1); 1285*b2167459SRichard Henderson 1286*b2167459SRichard Henderson tcg_gen_addi_tl(tcg_r1, tcg_rt, i); 1287*b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 1288*b2167459SRichard Henderson cond_free(&ctx->null_cond); 1289*b2167459SRichard Henderson 1290*b2167459SRichard Henderson return NO_EXIT; 1291*b2167459SRichard Henderson } 1292*b2167459SRichard Henderson 1293*b2167459SRichard Henderson static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn) 1294*b2167459SRichard Henderson { 1295*b2167459SRichard Henderson unsigned rb = extract32(insn, 21, 5); 1296*b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 1297*b2167459SRichard Henderson target_long i = assemble_16(insn); 1298*b2167459SRichard Henderson TCGv tcg_rt = dest_gpr(ctx, rt); 1299*b2167459SRichard Henderson 1300*b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 1301*b2167459SRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */ 1302*b2167459SRichard Henderson if (rb == 0) { 1303*b2167459SRichard Henderson tcg_gen_movi_tl(tcg_rt, i); 1304*b2167459SRichard Henderson } else { 1305*b2167459SRichard Henderson tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i); 1306*b2167459SRichard Henderson } 1307*b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 1308*b2167459SRichard Henderson cond_free(&ctx->null_cond); 1309*b2167459SRichard Henderson 1310*b2167459SRichard Henderson return NO_EXIT; 1311*b2167459SRichard Henderson } 1312*b2167459SRichard Henderson 131361766fe9SRichard Henderson static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn, 131461766fe9SRichard Henderson const DisasInsn table[], size_t n) 131561766fe9SRichard Henderson { 131661766fe9SRichard Henderson size_t i; 131761766fe9SRichard Henderson for (i = 0; i < n; ++i) { 131861766fe9SRichard Henderson if ((insn & table[i].mask) == table[i].insn) { 131961766fe9SRichard Henderson return table[i].trans(ctx, insn, &table[i]); 132061766fe9SRichard Henderson } 132161766fe9SRichard Henderson } 132261766fe9SRichard Henderson return gen_illegal(ctx); 132361766fe9SRichard Henderson } 132461766fe9SRichard Henderson 132561766fe9SRichard Henderson #define translate_table(ctx, insn, table) \ 132661766fe9SRichard Henderson translate_table_int(ctx, insn, table, ARRAY_SIZE(table)) 132761766fe9SRichard Henderson 132861766fe9SRichard Henderson static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) 132961766fe9SRichard Henderson { 133061766fe9SRichard Henderson uint32_t opc = extract32(insn, 26, 6); 133161766fe9SRichard Henderson 133261766fe9SRichard Henderson switch (opc) { 1333*b2167459SRichard Henderson case 0x02: 1334*b2167459SRichard Henderson return translate_table(ctx, insn, table_arith_log); 1335*b2167459SRichard Henderson case 0x08: 1336*b2167459SRichard Henderson return trans_ldil(ctx, insn); 1337*b2167459SRichard Henderson case 0x0A: 1338*b2167459SRichard Henderson return trans_addil(ctx, insn); 1339*b2167459SRichard Henderson case 0x0D: 1340*b2167459SRichard Henderson return trans_ldo(ctx, insn); 1341*b2167459SRichard Henderson case 0x24: 1342*b2167459SRichard Henderson return trans_cmpiclr(ctx, insn); 1343*b2167459SRichard Henderson case 0x25: 1344*b2167459SRichard Henderson return trans_subi(ctx, insn); 1345*b2167459SRichard Henderson case 0x2C: 1346*b2167459SRichard Henderson case 0x2D: 1347*b2167459SRichard Henderson return trans_addi(ctx, insn); 134861766fe9SRichard Henderson default: 134961766fe9SRichard Henderson break; 135061766fe9SRichard Henderson } 135161766fe9SRichard Henderson return gen_illegal(ctx); 135261766fe9SRichard Henderson } 135361766fe9SRichard Henderson 135461766fe9SRichard Henderson void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb) 135561766fe9SRichard Henderson { 135661766fe9SRichard Henderson HPPACPU *cpu = hppa_env_get_cpu(env); 135761766fe9SRichard Henderson CPUState *cs = CPU(cpu); 135861766fe9SRichard Henderson DisasContext ctx; 135961766fe9SRichard Henderson ExitStatus ret; 136061766fe9SRichard Henderson int num_insns, max_insns, i; 136161766fe9SRichard Henderson 136261766fe9SRichard Henderson ctx.tb = tb; 136361766fe9SRichard Henderson ctx.cs = cs; 136461766fe9SRichard Henderson ctx.iaoq_f = tb->pc; 136561766fe9SRichard Henderson ctx.iaoq_b = tb->cs_base; 136661766fe9SRichard Henderson ctx.singlestep_enabled = cs->singlestep_enabled; 136761766fe9SRichard Henderson 136861766fe9SRichard Henderson ctx.ntemps = 0; 136961766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) { 137061766fe9SRichard Henderson TCGV_UNUSED(ctx.temps[i]); 137161766fe9SRichard Henderson } 137261766fe9SRichard Henderson 137361766fe9SRichard Henderson /* Compute the maximum number of insns to execute, as bounded by 137461766fe9SRichard Henderson (1) icount, (2) single-stepping, (3) branch delay slots, or 137561766fe9SRichard Henderson (4) the number of insns remaining on the current page. */ 137661766fe9SRichard Henderson max_insns = tb->cflags & CF_COUNT_MASK; 137761766fe9SRichard Henderson if (max_insns == 0) { 137861766fe9SRichard Henderson max_insns = CF_COUNT_MASK; 137961766fe9SRichard Henderson } 138061766fe9SRichard Henderson if (ctx.singlestep_enabled || singlestep) { 138161766fe9SRichard Henderson max_insns = 1; 138261766fe9SRichard Henderson } else if (max_insns > TCG_MAX_INSNS) { 138361766fe9SRichard Henderson max_insns = TCG_MAX_INSNS; 138461766fe9SRichard Henderson } 138561766fe9SRichard Henderson 138661766fe9SRichard Henderson num_insns = 0; 138761766fe9SRichard Henderson gen_tb_start(tb); 138861766fe9SRichard Henderson 1389129e9cc3SRichard Henderson /* Seed the nullification status from PSW[N], as shown in TB->FLAGS. */ 1390129e9cc3SRichard Henderson ctx.null_cond = cond_make_f(); 1391129e9cc3SRichard Henderson ctx.psw_n_nonzero = false; 1392129e9cc3SRichard Henderson if (tb->flags & 1) { 1393129e9cc3SRichard Henderson ctx.null_cond.c = TCG_COND_ALWAYS; 1394129e9cc3SRichard Henderson ctx.psw_n_nonzero = true; 1395129e9cc3SRichard Henderson } 1396129e9cc3SRichard Henderson ctx.null_lab = NULL; 1397129e9cc3SRichard Henderson 139861766fe9SRichard Henderson do { 139961766fe9SRichard Henderson tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b); 140061766fe9SRichard Henderson num_insns++; 140161766fe9SRichard Henderson 140261766fe9SRichard Henderson if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) { 140361766fe9SRichard Henderson ret = gen_excp(&ctx, EXCP_DEBUG); 140461766fe9SRichard Henderson break; 140561766fe9SRichard Henderson } 140661766fe9SRichard Henderson if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { 140761766fe9SRichard Henderson gen_io_start(); 140861766fe9SRichard Henderson } 140961766fe9SRichard Henderson 141061766fe9SRichard Henderson { 141161766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 141261766fe9SRichard Henderson the page permissions for execute. */ 141361766fe9SRichard Henderson uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f); 141461766fe9SRichard Henderson 141561766fe9SRichard Henderson /* Set up the IA queue for the next insn. 141661766fe9SRichard Henderson This will be overwritten by a branch. */ 141761766fe9SRichard Henderson if (ctx.iaoq_b == -1) { 141861766fe9SRichard Henderson ctx.iaoq_n = -1; 141961766fe9SRichard Henderson ctx.iaoq_n_var = get_temp(&ctx); 142061766fe9SRichard Henderson tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4); 142161766fe9SRichard Henderson } else { 142261766fe9SRichard Henderson ctx.iaoq_n = ctx.iaoq_b + 4; 142361766fe9SRichard Henderson TCGV_UNUSED(ctx.iaoq_n_var); 142461766fe9SRichard Henderson } 142561766fe9SRichard Henderson 1426129e9cc3SRichard Henderson if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) { 1427129e9cc3SRichard Henderson ctx.null_cond.c = TCG_COND_NEVER; 1428129e9cc3SRichard Henderson ret = NO_EXIT; 1429129e9cc3SRichard Henderson } else { 143061766fe9SRichard Henderson ret = translate_one(&ctx, insn); 1431129e9cc3SRichard Henderson assert(ctx.null_lab == NULL); 1432129e9cc3SRichard Henderson } 143361766fe9SRichard Henderson } 143461766fe9SRichard Henderson 143561766fe9SRichard Henderson for (i = 0; i < ctx.ntemps; ++i) { 143661766fe9SRichard Henderson tcg_temp_free(ctx.temps[i]); 143761766fe9SRichard Henderson TCGV_UNUSED(ctx.temps[i]); 143861766fe9SRichard Henderson } 143961766fe9SRichard Henderson ctx.ntemps = 0; 144061766fe9SRichard Henderson 144161766fe9SRichard Henderson /* If we see non-linear instructions, exhaust instruction count, 144261766fe9SRichard Henderson or run out of buffer space, stop generation. */ 144361766fe9SRichard Henderson /* ??? The non-linear instruction restriction is purely due to 144461766fe9SRichard Henderson the debugging dump. Otherwise we *could* follow unconditional 144561766fe9SRichard Henderson branches within the same page. */ 144661766fe9SRichard Henderson if (ret == NO_EXIT 144761766fe9SRichard Henderson && (ctx.iaoq_b != ctx.iaoq_f + 4 144861766fe9SRichard Henderson || num_insns >= max_insns 144961766fe9SRichard Henderson || tcg_op_buf_full())) { 1450129e9cc3SRichard Henderson if (ctx.null_cond.c == TCG_COND_NEVER 1451129e9cc3SRichard Henderson || ctx.null_cond.c == TCG_COND_ALWAYS) { 1452129e9cc3SRichard Henderson nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS); 1453129e9cc3SRichard Henderson gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n); 1454129e9cc3SRichard Henderson ret = EXIT_GOTO_TB; 1455129e9cc3SRichard Henderson } else { 145661766fe9SRichard Henderson ret = EXIT_IAQ_N_STALE; 145761766fe9SRichard Henderson } 1458129e9cc3SRichard Henderson } 145961766fe9SRichard Henderson 146061766fe9SRichard Henderson ctx.iaoq_f = ctx.iaoq_b; 146161766fe9SRichard Henderson ctx.iaoq_b = ctx.iaoq_n; 146261766fe9SRichard Henderson if (ret == EXIT_NORETURN 146361766fe9SRichard Henderson || ret == EXIT_GOTO_TB 146461766fe9SRichard Henderson || ret == EXIT_IAQ_N_UPDATED) { 146561766fe9SRichard Henderson break; 146661766fe9SRichard Henderson } 146761766fe9SRichard Henderson if (ctx.iaoq_f == -1) { 146861766fe9SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b); 146961766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var); 1470129e9cc3SRichard Henderson nullify_save(&ctx); 147161766fe9SRichard Henderson ret = EXIT_IAQ_N_UPDATED; 147261766fe9SRichard Henderson break; 147361766fe9SRichard Henderson } 147461766fe9SRichard Henderson if (ctx.iaoq_b == -1) { 147561766fe9SRichard Henderson tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var); 147661766fe9SRichard Henderson } 147761766fe9SRichard Henderson } while (ret == NO_EXIT); 147861766fe9SRichard Henderson 147961766fe9SRichard Henderson if (tb->cflags & CF_LAST_IO) { 148061766fe9SRichard Henderson gen_io_end(); 148161766fe9SRichard Henderson } 148261766fe9SRichard Henderson 148361766fe9SRichard Henderson switch (ret) { 148461766fe9SRichard Henderson case EXIT_GOTO_TB: 148561766fe9SRichard Henderson case EXIT_NORETURN: 148661766fe9SRichard Henderson break; 148761766fe9SRichard Henderson case EXIT_IAQ_N_STALE: 148861766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f); 148961766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b); 1490129e9cc3SRichard Henderson nullify_save(&ctx); 149161766fe9SRichard Henderson /* FALLTHRU */ 149261766fe9SRichard Henderson case EXIT_IAQ_N_UPDATED: 149361766fe9SRichard Henderson if (ctx.singlestep_enabled) { 149461766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 149561766fe9SRichard Henderson } else { 149661766fe9SRichard Henderson tcg_gen_exit_tb(0); 149761766fe9SRichard Henderson } 149861766fe9SRichard Henderson break; 149961766fe9SRichard Henderson default: 150061766fe9SRichard Henderson abort(); 150161766fe9SRichard Henderson } 150261766fe9SRichard Henderson 150361766fe9SRichard Henderson gen_tb_end(tb, num_insns); 150461766fe9SRichard Henderson 150561766fe9SRichard Henderson tb->size = num_insns * 4; 150661766fe9SRichard Henderson tb->icount = num_insns; 150761766fe9SRichard Henderson 150861766fe9SRichard Henderson #ifdef DEBUG_DISAS 150961766fe9SRichard Henderson if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) 151061766fe9SRichard Henderson && qemu_log_in_addr_range(tb->pc)) { 151161766fe9SRichard Henderson qemu_log_lock(); 151261766fe9SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(tb->pc)); 151361766fe9SRichard Henderson log_target_disas(cs, tb->pc, tb->size, 1); 151461766fe9SRichard Henderson qemu_log("\n"); 151561766fe9SRichard Henderson qemu_log_unlock(); 151661766fe9SRichard Henderson } 151761766fe9SRichard Henderson #endif 151861766fe9SRichard Henderson } 151961766fe9SRichard Henderson 152061766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb, 152161766fe9SRichard Henderson target_ulong *data) 152261766fe9SRichard Henderson { 152361766fe9SRichard Henderson env->iaoq_f = data[0]; 152461766fe9SRichard Henderson if (data[1] != -1) { 152561766fe9SRichard Henderson env->iaoq_b = data[1]; 152661766fe9SRichard Henderson } 152761766fe9SRichard Henderson /* Since we were executing the instruction at IAOQ_F, and took some 152861766fe9SRichard Henderson sort of action that provoked the cpu_restore_state, we can infer 152961766fe9SRichard Henderson that the instruction was not nullified. */ 153061766fe9SRichard Henderson env->psw_n = 0; 153161766fe9SRichard Henderson } 1532