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 9d6ea4236SChetan Pant * version 2.1 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" 2574781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h" 26dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 270843563fSRichard Henderson #include "tcg/tcg-op-gvec.h" 2861766fe9SRichard Henderson #include "exec/helper-proto.h" 2961766fe9SRichard Henderson #include "exec/helper-gen.h" 30869051eaSRichard Henderson #include "exec/translator.h" 3161766fe9SRichard Henderson #include "exec/log.h" 3261766fe9SRichard Henderson 33d53106c9SRichard Henderson #define HELPER_H "helper.h" 34d53106c9SRichard Henderson #include "exec/helper-info.c.inc" 35d53106c9SRichard Henderson #undef HELPER_H 36d53106c9SRichard Henderson 37aac0f603SRichard Henderson /* Choose to use explicit sizes within this file. */ 38aac0f603SRichard Henderson #undef tcg_temp_new 39d53106c9SRichard Henderson 4061766fe9SRichard Henderson typedef struct DisasCond { 4161766fe9SRichard Henderson TCGCond c; 426fd0c7bcSRichard Henderson TCGv_i64 a0, a1; 4361766fe9SRichard Henderson } DisasCond; 4461766fe9SRichard Henderson 45bc921866SRichard Henderson typedef struct DisasIAQE { 46bc921866SRichard Henderson /* IASQ; may be null for no change from TB. */ 47bc921866SRichard Henderson TCGv_i64 space; 480d89cb7cSRichard Henderson /* IAOQ base; may be null for relative address. */ 49bc921866SRichard Henderson TCGv_i64 base; 500d89cb7cSRichard Henderson /* IAOQ addend; if base is null, relative to ctx->iaoq_first. */ 51bc921866SRichard Henderson int64_t disp; 52bc921866SRichard Henderson } DisasIAQE; 53bc921866SRichard Henderson 5461766fe9SRichard Henderson typedef struct DisasContext { 55d01a3625SRichard Henderson DisasContextBase base; 5661766fe9SRichard Henderson CPUState *cs; 5761766fe9SRichard Henderson 58bc921866SRichard Henderson /* IAQ_Front, IAQ_Back. */ 59bc921866SRichard Henderson DisasIAQE iaq_f, iaq_b; 60bc921866SRichard Henderson /* IAQ_Next, for jumps, otherwise null for simple advance. */ 61bc921866SRichard Henderson DisasIAQE iaq_j, *iaq_n; 6261766fe9SRichard Henderson 630d89cb7cSRichard Henderson /* IAOQ_Front at entry to TB. */ 640d89cb7cSRichard Henderson uint64_t iaoq_first; 650d89cb7cSRichard Henderson 6661766fe9SRichard Henderson DisasCond null_cond; 6761766fe9SRichard Henderson TCGLabel *null_lab; 6861766fe9SRichard Henderson 69a4db4a78SRichard Henderson TCGv_i64 zero; 70a4db4a78SRichard Henderson 711a19da0dSRichard Henderson uint32_t insn; 72494737b7SRichard Henderson uint32_t tb_flags; 733d68ee7bSRichard Henderson int mmu_idx; 743d68ee7bSRichard Henderson int privilege; 7561766fe9SRichard Henderson bool psw_n_nonzero; 76bd6243a3SRichard Henderson bool is_pa20; 7724638bd1SRichard Henderson bool insn_start_updated; 78217d1a5eSRichard Henderson 79217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 80217d1a5eSRichard Henderson MemOp unalign; 81217d1a5eSRichard Henderson #endif 8261766fe9SRichard Henderson } DisasContext; 8361766fe9SRichard Henderson 84217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 85217d1a5eSRichard Henderson #define UNALIGN(C) (C)->unalign 8617fe594cSRichard Henderson #define MMU_DISABLED(C) false 87217d1a5eSRichard Henderson #else 882d4afb03SRichard Henderson #define UNALIGN(C) MO_ALIGN 8917fe594cSRichard Henderson #define MMU_DISABLED(C) MMU_IDX_MMU_DISABLED((C)->mmu_idx) 90217d1a5eSRichard Henderson #endif 91217d1a5eSRichard Henderson 92e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 93451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val) 94e36f27efSRichard Henderson { 95881d1073SHelge Deller /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */ 96881d1073SHelge Deller if (ctx->is_pa20) { 97e36f27efSRichard Henderson if (val & PSW_SM_W) { 98881d1073SHelge Deller val |= PSW_W; 99881d1073SHelge Deller } 100881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_G); 101881d1073SHelge Deller } else { 102881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_O); 103e36f27efSRichard Henderson } 104e36f27efSRichard Henderson return val; 105e36f27efSRichard Henderson } 106e36f27efSRichard Henderson 107deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base. */ 108451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val) 109deee69a1SRichard Henderson { 110deee69a1SRichard Henderson return ~val; 111deee69a1SRichard Henderson } 112deee69a1SRichard Henderson 1131cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value 1141cd012a5SRichard Henderson we use for the final M. */ 115451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val) 1161cd012a5SRichard Henderson { 1171cd012a5SRichard Henderson return val & 2 ? (val & 1 ? -1 : 1) : 0; 1181cd012a5SRichard Henderson } 1191cd012a5SRichard Henderson 120740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify. */ 121451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val) 122740038d7SRichard Henderson { 123740038d7SRichard Henderson return val ? 1 : -1; 124740038d7SRichard Henderson } 125740038d7SRichard Henderson 126451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val) 127740038d7SRichard Henderson { 128740038d7SRichard Henderson return val ? -1 : 1; 129740038d7SRichard Henderson } 130740038d7SRichard Henderson 131740038d7SRichard Henderson /* Used for branch targets and fp memory ops. */ 132451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val) 13301afb7beSRichard Henderson { 13401afb7beSRichard Henderson return val << 2; 13501afb7beSRichard Henderson } 13601afb7beSRichard Henderson 1370588e061SRichard Henderson /* Used for assemble_21. */ 138451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val) 1390588e061SRichard Henderson { 1400588e061SRichard Henderson return val << 11; 1410588e061SRichard Henderson } 1420588e061SRichard Henderson 14372ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val) 14472ae4f2bSRichard Henderson { 14572ae4f2bSRichard Henderson /* 14672ae4f2bSRichard Henderson * Officially, 32 * x + 32 - y. 14772ae4f2bSRichard Henderson * Here, x is already in bit 5, and y is [4:0]. 14872ae4f2bSRichard Henderson * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1, 14972ae4f2bSRichard Henderson * with the overflow from bit 4 summing with x. 15072ae4f2bSRichard Henderson */ 15172ae4f2bSRichard Henderson return (val ^ 31) + 1; 15272ae4f2bSRichard Henderson } 15372ae4f2bSRichard Henderson 1544768c28eSRichard Henderson /* Expander for assemble_16a(s,cat(im10a,0),i). */ 1554768c28eSRichard Henderson static int expand_11a(DisasContext *ctx, int val) 1564768c28eSRichard Henderson { 1574768c28eSRichard Henderson /* 1584768c28eSRichard Henderson * @val is bit 0 and bits [4:15]. 1594768c28eSRichard Henderson * Swizzle thing around depending on PSW.W. 1604768c28eSRichard Henderson */ 1614768c28eSRichard Henderson int im10a = extract32(val, 1, 10); 1624768c28eSRichard Henderson int s = extract32(val, 11, 2); 1634768c28eSRichard Henderson int i = (-(val & 1) << 13) | (im10a << 3); 1644768c28eSRichard Henderson 1654768c28eSRichard Henderson if (ctx->tb_flags & PSW_W) { 1664768c28eSRichard Henderson i ^= s << 13; 1674768c28eSRichard Henderson } 1684768c28eSRichard Henderson return i; 1694768c28eSRichard Henderson } 1704768c28eSRichard Henderson 17146174e14SRichard Henderson /* Expander for assemble_16a(s,im11a,i). */ 17246174e14SRichard Henderson static int expand_12a(DisasContext *ctx, int val) 17346174e14SRichard Henderson { 17446174e14SRichard Henderson /* 17546174e14SRichard Henderson * @val is bit 0 and bits [3:15]. 17646174e14SRichard Henderson * Swizzle thing around depending on PSW.W. 17746174e14SRichard Henderson */ 17846174e14SRichard Henderson int im11a = extract32(val, 1, 11); 17946174e14SRichard Henderson int s = extract32(val, 12, 2); 18046174e14SRichard Henderson int i = (-(val & 1) << 13) | (im11a << 2); 18146174e14SRichard Henderson 18246174e14SRichard Henderson if (ctx->tb_flags & PSW_W) { 18346174e14SRichard Henderson i ^= s << 13; 18446174e14SRichard Henderson } 18546174e14SRichard Henderson return i; 18646174e14SRichard Henderson } 18746174e14SRichard Henderson 18872bace2dSRichard Henderson /* Expander for assemble_16(s,im14). */ 18972bace2dSRichard Henderson static int expand_16(DisasContext *ctx, int val) 19072bace2dSRichard Henderson { 19172bace2dSRichard Henderson /* 19272bace2dSRichard Henderson * @val is bits [0:15], containing both im14 and s. 19372bace2dSRichard Henderson * Swizzle thing around depending on PSW.W. 19472bace2dSRichard Henderson */ 19572bace2dSRichard Henderson int s = extract32(val, 14, 2); 19672bace2dSRichard Henderson int i = (-(val & 1) << 13) | extract32(val, 1, 13); 19772bace2dSRichard Henderson 19872bace2dSRichard Henderson if (ctx->tb_flags & PSW_W) { 19972bace2dSRichard Henderson i ^= s << 13; 20072bace2dSRichard Henderson } 20172bace2dSRichard Henderson return i; 20272bace2dSRichard Henderson } 20372bace2dSRichard Henderson 20472bace2dSRichard Henderson /* The sp field is only present with !PSW_W. */ 20572bace2dSRichard Henderson static int sp0_if_wide(DisasContext *ctx, int sp) 20672bace2dSRichard Henderson { 20772bace2dSRichard Henderson return ctx->tb_flags & PSW_W ? 0 : sp; 20872bace2dSRichard Henderson } 20972bace2dSRichard Henderson 210c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */ 211c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val) 212c65c3ee1SRichard Henderson { 213c65c3ee1SRichard Henderson return val ? val : 4; /* 0 == "*<<" */ 214c65c3ee1SRichard Henderson } 215c65c3ee1SRichard Henderson 21682d0c831SRichard Henderson /* 21782d0c831SRichard Henderson * In many places pa1.x did not decode the bit that later became 21882d0c831SRichard Henderson * the pa2.0 D bit. Suppress D unless the cpu is pa2.0. 21982d0c831SRichard Henderson */ 22082d0c831SRichard Henderson static int pa20_d(DisasContext *ctx, int val) 22182d0c831SRichard Henderson { 22282d0c831SRichard Henderson return ctx->is_pa20 & val; 22382d0c831SRichard Henderson } 22401afb7beSRichard Henderson 22540f9f908SRichard Henderson /* Include the auto-generated decoder. */ 226abff1abfSPaolo Bonzini #include "decode-insns.c.inc" 22740f9f908SRichard Henderson 22861766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 22961766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 230869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 23161766fe9SRichard Henderson 23261766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 23361766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 234869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 23561766fe9SRichard Henderson 236e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 237e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 238e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 239c5d0aec2SRichard Henderson #define DISAS_EXIT DISAS_TARGET_3 240e1b5a5edSRichard Henderson 24161766fe9SRichard Henderson /* global register indexes */ 2426fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32]; 24333423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 244494737b7SRichard Henderson static TCGv_i64 cpu_srH; 2456fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f; 2466fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b; 247c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 248c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 2496fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar; 2506fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n; 2516fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v; 2526fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb; 2536fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb; 25461766fe9SRichard Henderson 25561766fe9SRichard Henderson void hppa_translate_init(void) 25661766fe9SRichard Henderson { 25761766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 25861766fe9SRichard Henderson 2596fd0c7bcSRichard Henderson typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 26061766fe9SRichard Henderson static const GlobalVar vars[] = { 26135136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 26261766fe9SRichard Henderson DEF_VAR(psw_n), 26361766fe9SRichard Henderson DEF_VAR(psw_v), 26461766fe9SRichard Henderson DEF_VAR(psw_cb), 26561766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 26661766fe9SRichard Henderson DEF_VAR(iaoq_f), 26761766fe9SRichard Henderson DEF_VAR(iaoq_b), 26861766fe9SRichard Henderson }; 26961766fe9SRichard Henderson 27061766fe9SRichard Henderson #undef DEF_VAR 27161766fe9SRichard Henderson 27261766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 27361766fe9SRichard Henderson static const char gr_names[32][4] = { 27461766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 27561766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 27661766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 27761766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 27861766fe9SRichard Henderson }; 27933423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 280494737b7SRichard Henderson static const char sr_names[5][4] = { 281494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 28233423472SRichard Henderson }; 28361766fe9SRichard Henderson 28461766fe9SRichard Henderson int i; 28561766fe9SRichard Henderson 286f764718dSRichard Henderson cpu_gr[0] = NULL; 28761766fe9SRichard Henderson for (i = 1; i < 32; i++) { 288ad75a51eSRichard Henderson cpu_gr[i] = tcg_global_mem_new(tcg_env, 28961766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 29061766fe9SRichard Henderson gr_names[i]); 29161766fe9SRichard Henderson } 29233423472SRichard Henderson for (i = 0; i < 4; i++) { 293ad75a51eSRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 29433423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 29533423472SRichard Henderson sr_names[i]); 29633423472SRichard Henderson } 297ad75a51eSRichard Henderson cpu_srH = tcg_global_mem_new_i64(tcg_env, 298494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 299494737b7SRichard Henderson sr_names[4]); 30061766fe9SRichard Henderson 30161766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 30261766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 303ad75a51eSRichard Henderson *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 30461766fe9SRichard Henderson } 305c301f34eSRichard Henderson 306ad75a51eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 307c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 308c301f34eSRichard Henderson "iasq_f"); 309ad75a51eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 310c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 311c301f34eSRichard Henderson "iasq_b"); 31261766fe9SRichard Henderson } 31361766fe9SRichard Henderson 314f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg) 315f5b5c857SRichard Henderson { 31624638bd1SRichard Henderson assert(!ctx->insn_start_updated); 31724638bd1SRichard Henderson ctx->insn_start_updated = true; 31824638bd1SRichard Henderson tcg_set_insn_start_param(ctx->base.insn_start, 2, breg); 319f5b5c857SRichard Henderson } 320f5b5c857SRichard Henderson 321129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 322129e9cc3SRichard Henderson { 323f764718dSRichard Henderson return (DisasCond){ 324f764718dSRichard Henderson .c = TCG_COND_NEVER, 325f764718dSRichard Henderson .a0 = NULL, 326f764718dSRichard Henderson .a1 = NULL, 327f764718dSRichard Henderson }; 328129e9cc3SRichard Henderson } 329129e9cc3SRichard Henderson 330df0232feSRichard Henderson static DisasCond cond_make_t(void) 331df0232feSRichard Henderson { 332df0232feSRichard Henderson return (DisasCond){ 333df0232feSRichard Henderson .c = TCG_COND_ALWAYS, 334df0232feSRichard Henderson .a0 = NULL, 335df0232feSRichard Henderson .a1 = NULL, 336df0232feSRichard Henderson }; 337df0232feSRichard Henderson } 338df0232feSRichard Henderson 339129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 340129e9cc3SRichard Henderson { 341f764718dSRichard Henderson return (DisasCond){ 342f764718dSRichard Henderson .c = TCG_COND_NE, 343f764718dSRichard Henderson .a0 = cpu_psw_n, 3446fd0c7bcSRichard Henderson .a1 = tcg_constant_i64(0) 345f764718dSRichard Henderson }; 346129e9cc3SRichard Henderson } 347129e9cc3SRichard Henderson 3484c42fd0dSRichard Henderson static DisasCond cond_make_tt(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 349b47a4a02SSven Schnelle { 350b47a4a02SSven Schnelle assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 3514fe9533aSRichard Henderson return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 3524fe9533aSRichard Henderson } 3534fe9533aSRichard Henderson 3544c42fd0dSRichard Henderson static DisasCond cond_make_ti(TCGCond c, TCGv_i64 a0, uint64_t imm) 3554fe9533aSRichard Henderson { 3564c42fd0dSRichard Henderson return cond_make_tt(c, a0, tcg_constant_i64(imm)); 357b47a4a02SSven Schnelle } 358b47a4a02SSven Schnelle 3594c42fd0dSRichard Henderson static DisasCond cond_make_vi(TCGCond c, TCGv_i64 a0, uint64_t imm) 360129e9cc3SRichard Henderson { 361aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3626fd0c7bcSRichard Henderson tcg_gen_mov_i64(tmp, a0); 3634c42fd0dSRichard Henderson return cond_make_ti(c, tmp, imm); 364129e9cc3SRichard Henderson } 365129e9cc3SRichard Henderson 3664c42fd0dSRichard Henderson static DisasCond cond_make_vv(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 367129e9cc3SRichard Henderson { 368aac0f603SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 369aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 370129e9cc3SRichard Henderson 3716fd0c7bcSRichard Henderson tcg_gen_mov_i64(t0, a0); 3726fd0c7bcSRichard Henderson tcg_gen_mov_i64(t1, a1); 3734c42fd0dSRichard Henderson return cond_make_tt(c, t0, t1); 374129e9cc3SRichard Henderson } 375129e9cc3SRichard Henderson 376129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 377129e9cc3SRichard Henderson { 378129e9cc3SRichard Henderson switch (cond->c) { 379129e9cc3SRichard Henderson default: 380f764718dSRichard Henderson cond->a0 = NULL; 381f764718dSRichard Henderson cond->a1 = NULL; 382129e9cc3SRichard Henderson /* fallthru */ 383129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 384129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 385129e9cc3SRichard Henderson break; 386129e9cc3SRichard Henderson case TCG_COND_NEVER: 387129e9cc3SRichard Henderson break; 388129e9cc3SRichard Henderson } 389129e9cc3SRichard Henderson } 390129e9cc3SRichard Henderson 3916fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 39261766fe9SRichard Henderson { 39361766fe9SRichard Henderson if (reg == 0) { 394bc3da3cfSRichard Henderson return ctx->zero; 39561766fe9SRichard Henderson } else { 39661766fe9SRichard Henderson return cpu_gr[reg]; 39761766fe9SRichard Henderson } 39861766fe9SRichard Henderson } 39961766fe9SRichard Henderson 4006fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 40161766fe9SRichard Henderson { 402129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 403aac0f603SRichard Henderson return tcg_temp_new_i64(); 40461766fe9SRichard Henderson } else { 40561766fe9SRichard Henderson return cpu_gr[reg]; 40661766fe9SRichard Henderson } 40761766fe9SRichard Henderson } 40861766fe9SRichard Henderson 4096fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 410129e9cc3SRichard Henderson { 411129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 4126fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 413129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 414129e9cc3SRichard Henderson } else { 4156fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 416129e9cc3SRichard Henderson } 417129e9cc3SRichard Henderson } 418129e9cc3SRichard Henderson 4196fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 420129e9cc3SRichard Henderson { 421129e9cc3SRichard Henderson if (reg != 0) { 422129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 423129e9cc3SRichard Henderson } 424129e9cc3SRichard Henderson } 425129e9cc3SRichard Henderson 426e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 42796d6407fSRichard Henderson # define HI_OFS 0 42896d6407fSRichard Henderson # define LO_OFS 4 42996d6407fSRichard Henderson #else 43096d6407fSRichard Henderson # define HI_OFS 4 43196d6407fSRichard Henderson # define LO_OFS 0 43296d6407fSRichard Henderson #endif 43396d6407fSRichard Henderson 43496d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 43596d6407fSRichard Henderson { 43696d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 437ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 43896d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 43996d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 44096d6407fSRichard Henderson return ret; 44196d6407fSRichard Henderson } 44296d6407fSRichard Henderson 443ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 444ebe9383cSRichard Henderson { 445ebe9383cSRichard Henderson if (rt == 0) { 4460992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 4470992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 4480992a930SRichard Henderson return ret; 449ebe9383cSRichard Henderson } else { 450ebe9383cSRichard Henderson return load_frw_i32(rt); 451ebe9383cSRichard Henderson } 452ebe9383cSRichard Henderson } 453ebe9383cSRichard Henderson 454ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 455ebe9383cSRichard Henderson { 456ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4570992a930SRichard Henderson if (rt == 0) { 4580992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4590992a930SRichard Henderson } else { 460ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 461ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 462ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 463ebe9383cSRichard Henderson } 4640992a930SRichard Henderson return ret; 465ebe9383cSRichard Henderson } 466ebe9383cSRichard Henderson 46796d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 46896d6407fSRichard Henderson { 469ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 47096d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 47196d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 47296d6407fSRichard Henderson } 47396d6407fSRichard Henderson 47496d6407fSRichard Henderson #undef HI_OFS 47596d6407fSRichard Henderson #undef LO_OFS 47696d6407fSRichard Henderson 47796d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 47896d6407fSRichard Henderson { 47996d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 480ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 48196d6407fSRichard Henderson return ret; 48296d6407fSRichard Henderson } 48396d6407fSRichard Henderson 484ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 485ebe9383cSRichard Henderson { 486ebe9383cSRichard Henderson if (rt == 0) { 4870992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4880992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4890992a930SRichard Henderson return ret; 490ebe9383cSRichard Henderson } else { 491ebe9383cSRichard Henderson return load_frd(rt); 492ebe9383cSRichard Henderson } 493ebe9383cSRichard Henderson } 494ebe9383cSRichard Henderson 49596d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 49696d6407fSRichard Henderson { 497ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 49896d6407fSRichard Henderson } 49996d6407fSRichard Henderson 50033423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 50133423472SRichard Henderson { 50233423472SRichard Henderson #ifdef CONFIG_USER_ONLY 50333423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 50433423472SRichard Henderson #else 50533423472SRichard Henderson if (reg < 4) { 50633423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 507494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 508494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 50933423472SRichard Henderson } else { 510ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 51133423472SRichard Henderson } 51233423472SRichard Henderson #endif 51333423472SRichard Henderson } 51433423472SRichard Henderson 515129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 516129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 517129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 518129e9cc3SRichard Henderson { 519129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 520129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 521129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 522129e9cc3SRichard Henderson 523129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 524129e9cc3SRichard Henderson 525129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 5266e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 527aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 5286fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 529129e9cc3SRichard Henderson } 530129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 531129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 532129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 533129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 534129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 5356fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 536129e9cc3SRichard Henderson } 537129e9cc3SRichard Henderson 5386fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 539129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 540129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 541129e9cc3SRichard Henderson } 542129e9cc3SRichard Henderson } 543129e9cc3SRichard Henderson 544129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 545129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 546129e9cc3SRichard Henderson { 547129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 548129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 5496fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 550129e9cc3SRichard Henderson } 551129e9cc3SRichard Henderson return; 552129e9cc3SRichard Henderson } 5536e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 5546fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 555129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 556129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 557129e9cc3SRichard Henderson } 558129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 559129e9cc3SRichard Henderson } 560129e9cc3SRichard Henderson 561129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 562129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 563129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 564129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 565129e9cc3SRichard Henderson { 566129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 5676fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 568129e9cc3SRichard Henderson } 569129e9cc3SRichard Henderson } 570129e9cc3SRichard Henderson 571129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 57240f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 57340f9f908SRichard Henderson it may be tail-called from a translate function. */ 57431234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 575129e9cc3SRichard Henderson { 576129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 57731234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 578129e9cc3SRichard Henderson 579f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 580f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 581f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 582f49b3537SRichard Henderson 583129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 584129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 585129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 586129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 58731234768SRichard Henderson return true; 588129e9cc3SRichard Henderson } 589129e9cc3SRichard Henderson ctx->null_lab = NULL; 590129e9cc3SRichard Henderson 591129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 592129e9cc3SRichard Henderson /* The next instruction will be unconditional, 593129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 594129e9cc3SRichard Henderson gen_set_label(null_lab); 595129e9cc3SRichard Henderson } else { 596129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 597129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 598129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 599129e9cc3SRichard Henderson label we have the proper value in place. */ 600129e9cc3SRichard Henderson nullify_save(ctx); 601129e9cc3SRichard Henderson gen_set_label(null_lab); 602129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 603129e9cc3SRichard Henderson } 604869051eaSRichard Henderson if (status == DISAS_NORETURN) { 60531234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 606129e9cc3SRichard Henderson } 60731234768SRichard Henderson return true; 608129e9cc3SRichard Henderson } 609129e9cc3SRichard Henderson 610bc921866SRichard Henderson static bool iaqe_variable(const DisasIAQE *e) 611bc921866SRichard Henderson { 612bc921866SRichard Henderson return e->base || e->space; 613bc921866SRichard Henderson } 614bc921866SRichard Henderson 615bc921866SRichard Henderson static DisasIAQE iaqe_incr(const DisasIAQE *e, int64_t disp) 616bc921866SRichard Henderson { 617bc921866SRichard Henderson return (DisasIAQE){ 618bc921866SRichard Henderson .space = e->space, 619bc921866SRichard Henderson .base = e->base, 620bc921866SRichard Henderson .disp = e->disp + disp, 621bc921866SRichard Henderson }; 622bc921866SRichard Henderson } 623bc921866SRichard Henderson 624bc921866SRichard Henderson static DisasIAQE iaqe_branchi(DisasContext *ctx, int64_t disp) 625bc921866SRichard Henderson { 626bc921866SRichard Henderson return (DisasIAQE){ 627bc921866SRichard Henderson .space = ctx->iaq_b.space, 628bc921866SRichard Henderson .disp = ctx->iaq_f.disp + 8 + disp, 629bc921866SRichard Henderson }; 630bc921866SRichard Henderson } 631bc921866SRichard Henderson 632bc921866SRichard Henderson static DisasIAQE iaqe_next_absv(DisasContext *ctx, TCGv_i64 var) 633bc921866SRichard Henderson { 634bc921866SRichard Henderson return (DisasIAQE){ 635bc921866SRichard Henderson .space = ctx->iaq_b.space, 636bc921866SRichard Henderson .base = var, 637bc921866SRichard Henderson }; 638bc921866SRichard Henderson } 639bc921866SRichard Henderson 6406fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 641bc921866SRichard Henderson const DisasIAQE *src) 64261766fe9SRichard Henderson { 6437d50b696SSven Schnelle uint64_t mask = gva_offset_mask(ctx->tb_flags); 644f13bf343SRichard Henderson 645bc921866SRichard Henderson if (src->base == NULL) { 6460d89cb7cSRichard Henderson tcg_gen_movi_i64(dest, (ctx->iaoq_first + src->disp) & mask); 647bc921866SRichard Henderson } else if (src->disp == 0) { 648bc921866SRichard Henderson tcg_gen_andi_i64(dest, src->base, mask); 64961766fe9SRichard Henderson } else { 650bc921866SRichard Henderson tcg_gen_addi_i64(dest, src->base, src->disp); 651bc921866SRichard Henderson tcg_gen_andi_i64(dest, dest, mask); 65261766fe9SRichard Henderson } 65361766fe9SRichard Henderson } 65461766fe9SRichard Henderson 655bc921866SRichard Henderson static void install_iaq_entries(DisasContext *ctx, const DisasIAQE *f, 656bc921866SRichard Henderson const DisasIAQE *b) 65785e6cda0SRichard Henderson { 658bc921866SRichard Henderson DisasIAQE b_next; 65985e6cda0SRichard Henderson 660bc921866SRichard Henderson if (b == NULL) { 661bc921866SRichard Henderson b_next = iaqe_incr(f, 4); 662bc921866SRichard Henderson b = &b_next; 66385e6cda0SRichard Henderson } 664bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f); 665bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b); 666bc921866SRichard Henderson if (f->space) { 667bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, f->space); 668588deedaSRichard Henderson } 669bc921866SRichard Henderson if (b->space || f->space) { 670bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, b->space ? : f->space); 671588deedaSRichard Henderson } 67285e6cda0SRichard Henderson } 67385e6cda0SRichard Henderson 67443541db0SRichard Henderson static void install_link(DisasContext *ctx, unsigned link, bool with_sr0) 67543541db0SRichard Henderson { 67643541db0SRichard Henderson tcg_debug_assert(ctx->null_cond.c == TCG_COND_NEVER); 67743541db0SRichard Henderson if (!link) { 67843541db0SRichard Henderson return; 67943541db0SRichard Henderson } 6800d89cb7cSRichard Henderson DisasIAQE next = iaqe_incr(&ctx->iaq_b, 4); 6810d89cb7cSRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], &next); 68243541db0SRichard Henderson #ifndef CONFIG_USER_ONLY 68343541db0SRichard Henderson if (with_sr0) { 68443541db0SRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_b); 68543541db0SRichard Henderson } 68643541db0SRichard Henderson #endif 68743541db0SRichard Henderson } 68843541db0SRichard Henderson 68961766fe9SRichard Henderson static void gen_excp_1(int exception) 69061766fe9SRichard Henderson { 691ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 69261766fe9SRichard Henderson } 69361766fe9SRichard Henderson 69431234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 69561766fe9SRichard Henderson { 696bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_f, &ctx->iaq_b); 697129e9cc3SRichard Henderson nullify_save(ctx); 69861766fe9SRichard Henderson gen_excp_1(exception); 69931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 70061766fe9SRichard Henderson } 70161766fe9SRichard Henderson 70231234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 7031a19da0dSRichard Henderson { 70431234768SRichard Henderson nullify_over(ctx); 7056fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 706ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 70731234768SRichard Henderson gen_excp(ctx, exc); 70831234768SRichard Henderson return nullify_end(ctx); 7091a19da0dSRichard Henderson } 7101a19da0dSRichard Henderson 71131234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 71261766fe9SRichard Henderson { 71331234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 71461766fe9SRichard Henderson } 71561766fe9SRichard Henderson 71640f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 71740f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 71840f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 71940f9f908SRichard Henderson #else 720e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 721e1b5a5edSRichard Henderson do { \ 722e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 72331234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 724e1b5a5edSRichard Henderson } \ 725e1b5a5edSRichard Henderson } while (0) 72640f9f908SRichard Henderson #endif 727e1b5a5edSRichard Henderson 728bc921866SRichard Henderson static bool use_goto_tb(DisasContext *ctx, const DisasIAQE *f, 729bc921866SRichard Henderson const DisasIAQE *b) 73061766fe9SRichard Henderson { 731bc921866SRichard Henderson return (!iaqe_variable(f) && 732bc921866SRichard Henderson (b == NULL || !iaqe_variable(b)) && 7330d89cb7cSRichard Henderson translator_use_goto_tb(&ctx->base, ctx->iaoq_first + f->disp)); 73461766fe9SRichard Henderson } 73561766fe9SRichard Henderson 736129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 737129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 738129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 739129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 740129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 741129e9cc3SRichard Henderson { 742f9b11bc2SRichard Henderson return (!(tb_cflags(ctx->base.tb) & CF_BP_PAGE) 743bc921866SRichard Henderson && !iaqe_variable(&ctx->iaq_b) 7440d89cb7cSRichard Henderson && (((ctx->iaoq_first + ctx->iaq_b.disp) ^ ctx->iaoq_first) 7450d89cb7cSRichard Henderson & TARGET_PAGE_MASK) == 0); 746129e9cc3SRichard Henderson } 747129e9cc3SRichard Henderson 74861766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 749bc921866SRichard Henderson const DisasIAQE *f, const DisasIAQE *b) 75061766fe9SRichard Henderson { 751bc921866SRichard Henderson if (use_goto_tb(ctx, f, b)) { 75261766fe9SRichard Henderson tcg_gen_goto_tb(which); 753bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 75407ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 75561766fe9SRichard Henderson } else { 756bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 7577f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 75861766fe9SRichard Henderson } 75961766fe9SRichard Henderson } 76061766fe9SRichard Henderson 761b47a4a02SSven Schnelle static bool cond_need_sv(int c) 762b47a4a02SSven Schnelle { 763b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 764b47a4a02SSven Schnelle } 765b47a4a02SSven Schnelle 766b47a4a02SSven Schnelle static bool cond_need_cb(int c) 767b47a4a02SSven Schnelle { 768b47a4a02SSven Schnelle return c == 4 || c == 5; 769b47a4a02SSven Schnelle } 770b47a4a02SSven Schnelle 771b47a4a02SSven Schnelle /* 772b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 773b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 774b47a4a02SSven Schnelle */ 775b2167459SRichard Henderson 776a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 777fe2d066aSRichard Henderson TCGv_i64 res, TCGv_i64 uv, TCGv_i64 sv) 778b2167459SRichard Henderson { 779d6d46be1SRichard Henderson TCGCond sign_cond, zero_cond; 780d6d46be1SRichard Henderson uint64_t sign_imm, zero_imm; 781b2167459SRichard Henderson DisasCond cond; 7826fd0c7bcSRichard Henderson TCGv_i64 tmp; 783b2167459SRichard Henderson 784d6d46be1SRichard Henderson if (d) { 785d6d46be1SRichard Henderson /* 64-bit condition. */ 786d6d46be1SRichard Henderson sign_imm = 0; 787d6d46be1SRichard Henderson sign_cond = TCG_COND_LT; 788d6d46be1SRichard Henderson zero_imm = 0; 789d6d46be1SRichard Henderson zero_cond = TCG_COND_EQ; 790d6d46be1SRichard Henderson } else { 791d6d46be1SRichard Henderson /* 32-bit condition. */ 792d6d46be1SRichard Henderson sign_imm = 1ull << 31; 793d6d46be1SRichard Henderson sign_cond = TCG_COND_TSTNE; 794d6d46be1SRichard Henderson zero_imm = UINT32_MAX; 795d6d46be1SRichard Henderson zero_cond = TCG_COND_TSTEQ; 796d6d46be1SRichard Henderson } 797d6d46be1SRichard Henderson 798b2167459SRichard Henderson switch (cf >> 1) { 799b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 800b2167459SRichard Henderson cond = cond_make_f(); 801b2167459SRichard Henderson break; 802b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 803d6d46be1SRichard Henderson cond = cond_make_vi(zero_cond, res, zero_imm); 804b2167459SRichard Henderson break; 805b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 806aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 8076fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 808d6d46be1SRichard Henderson cond = cond_make_ti(sign_cond, tmp, sign_imm); 809b2167459SRichard Henderson break; 810b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 811b47a4a02SSven Schnelle /* 812b47a4a02SSven Schnelle * Simplify: 813b47a4a02SSven Schnelle * (N ^ V) | Z 814b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 815b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 816d6d46be1SRichard Henderson * ((res ^ sv) < 0 ? 1 : !res) 817d6d46be1SRichard Henderson * !((res ^ sv) < 0 ? 0 : res) 818b47a4a02SSven Schnelle */ 819aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 820d6d46be1SRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 821d6d46be1SRichard Henderson tcg_gen_movcond_i64(sign_cond, tmp, 822d6d46be1SRichard Henderson tmp, tcg_constant_i64(sign_imm), 823d6d46be1SRichard Henderson ctx->zero, res); 824d6d46be1SRichard Henderson cond = cond_make_ti(zero_cond, tmp, zero_imm); 825b2167459SRichard Henderson break; 826fe2d066aSRichard Henderson case 4: /* NUV / UV (!UV / UV) */ 8274c42fd0dSRichard Henderson cond = cond_make_vi(TCG_COND_EQ, uv, 0); 828b2167459SRichard Henderson break; 829fe2d066aSRichard Henderson case 5: /* ZNV / VNZ (!UV | Z / UV & !Z) */ 830aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 831fe2d066aSRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, tmp, uv, ctx->zero, ctx->zero, res); 832d6d46be1SRichard Henderson cond = cond_make_ti(zero_cond, tmp, zero_imm); 833b2167459SRichard Henderson break; 834b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 835d6d46be1SRichard Henderson cond = cond_make_vi(sign_cond, sv, sign_imm); 836b2167459SRichard Henderson break; 837b2167459SRichard Henderson case 7: /* OD / EV */ 838d6d46be1SRichard Henderson cond = cond_make_vi(TCG_COND_TSTNE, res, 1); 839b2167459SRichard Henderson break; 840b2167459SRichard Henderson default: 841b2167459SRichard Henderson g_assert_not_reached(); 842b2167459SRichard Henderson } 843b2167459SRichard Henderson if (cf & 1) { 844b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 845b2167459SRichard Henderson } 846b2167459SRichard Henderson 847b2167459SRichard Henderson return cond; 848b2167459SRichard Henderson } 849b2167459SRichard Henderson 850b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 851b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 852b2167459SRichard Henderson deleted as unused. */ 853b2167459SRichard Henderson 8544fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 8556fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 8566fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 857b2167459SRichard Henderson { 8584fe9533aSRichard Henderson TCGCond tc; 8594fe9533aSRichard Henderson bool ext_uns; 860b2167459SRichard Henderson 861b2167459SRichard Henderson switch (cf >> 1) { 862b2167459SRichard Henderson case 1: /* = / <> */ 8634fe9533aSRichard Henderson tc = TCG_COND_EQ; 8644fe9533aSRichard Henderson ext_uns = true; 865b2167459SRichard Henderson break; 866b2167459SRichard Henderson case 2: /* < / >= */ 8674fe9533aSRichard Henderson tc = TCG_COND_LT; 8684fe9533aSRichard Henderson ext_uns = false; 869b2167459SRichard Henderson break; 870b2167459SRichard Henderson case 3: /* <= / > */ 8714fe9533aSRichard Henderson tc = TCG_COND_LE; 8724fe9533aSRichard Henderson ext_uns = false; 873b2167459SRichard Henderson break; 874b2167459SRichard Henderson case 4: /* << / >>= */ 8754fe9533aSRichard Henderson tc = TCG_COND_LTU; 8764fe9533aSRichard Henderson ext_uns = true; 877b2167459SRichard Henderson break; 878b2167459SRichard Henderson case 5: /* <<= / >> */ 8794fe9533aSRichard Henderson tc = TCG_COND_LEU; 8804fe9533aSRichard Henderson ext_uns = true; 881b2167459SRichard Henderson break; 882b2167459SRichard Henderson default: 883a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 884b2167459SRichard Henderson } 885b2167459SRichard Henderson 8864fe9533aSRichard Henderson if (cf & 1) { 8874fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 8884fe9533aSRichard Henderson } 88982d0c831SRichard Henderson if (!d) { 890aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 891aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 8924fe9533aSRichard Henderson 8934fe9533aSRichard Henderson if (ext_uns) { 8946fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 8956fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 8964fe9533aSRichard Henderson } else { 8976fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 8986fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 8994fe9533aSRichard Henderson } 9004c42fd0dSRichard Henderson return cond_make_tt(tc, t1, t2); 9014fe9533aSRichard Henderson } 9024c42fd0dSRichard Henderson return cond_make_vv(tc, in1, in2); 903b2167459SRichard Henderson } 904b2167459SRichard Henderson 905df0232feSRichard Henderson /* 906df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 907df0232feSRichard Henderson * computed, and use of them is undefined. 908df0232feSRichard Henderson * 909df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 910df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 911df0232feSRichard Henderson * how cases c={2,3} are treated. 912df0232feSRichard Henderson */ 913b2167459SRichard Henderson 914b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 9156fd0c7bcSRichard Henderson TCGv_i64 res) 916b2167459SRichard Henderson { 917b5af8423SRichard Henderson TCGCond tc; 918fbe65c64SRichard Henderson uint64_t imm; 919a751eb31SRichard Henderson 920fbe65c64SRichard Henderson switch (cf >> 1) { 921fbe65c64SRichard Henderson case 0: /* never / always */ 922fbe65c64SRichard Henderson case 4: /* undef, C */ 923fbe65c64SRichard Henderson case 5: /* undef, C & !Z */ 924fbe65c64SRichard Henderson case 6: /* undef, V */ 925fbe65c64SRichard Henderson return cf & 1 ? cond_make_t() : cond_make_f(); 926fbe65c64SRichard Henderson case 1: /* == / <> */ 927fbe65c64SRichard Henderson tc = d ? TCG_COND_EQ : TCG_COND_TSTEQ; 928fbe65c64SRichard Henderson imm = d ? 0 : UINT32_MAX; 929b5af8423SRichard Henderson break; 930fbe65c64SRichard Henderson case 2: /* < / >= */ 931fbe65c64SRichard Henderson tc = d ? TCG_COND_LT : TCG_COND_TSTNE; 932fbe65c64SRichard Henderson imm = d ? 0 : 1ull << 31; 933b5af8423SRichard Henderson break; 934fbe65c64SRichard Henderson case 3: /* <= / > */ 935fbe65c64SRichard Henderson tc = cf & 1 ? TCG_COND_GT : TCG_COND_LE; 93682d0c831SRichard Henderson if (!d) { 937aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 9386fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 9394c42fd0dSRichard Henderson return cond_make_ti(tc, tmp, 0); 940b5af8423SRichard Henderson } 9414c42fd0dSRichard Henderson return cond_make_vi(tc, res, 0); 942fbe65c64SRichard Henderson case 7: /* OD / EV */ 943fbe65c64SRichard Henderson tc = TCG_COND_TSTNE; 944fbe65c64SRichard Henderson imm = 1; 945fbe65c64SRichard Henderson break; 946fbe65c64SRichard Henderson default: 947fbe65c64SRichard Henderson g_assert_not_reached(); 948fbe65c64SRichard Henderson } 949fbe65c64SRichard Henderson if (cf & 1) { 950fbe65c64SRichard Henderson tc = tcg_invert_cond(tc); 951fbe65c64SRichard Henderson } 952fbe65c64SRichard Henderson return cond_make_vi(tc, res, imm); 953b2167459SRichard Henderson } 954b2167459SRichard Henderson 95598cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 95698cd9ca7SRichard Henderson 9574fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 9586fd0c7bcSRichard Henderson TCGv_i64 res) 95998cd9ca7SRichard Henderson { 96098cd9ca7SRichard Henderson unsigned c, f; 96198cd9ca7SRichard Henderson 96298cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 96398cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 96498cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 96598cd9ca7SRichard Henderson c = orig & 3; 96698cd9ca7SRichard Henderson if (c == 3) { 96798cd9ca7SRichard Henderson c = 7; 96898cd9ca7SRichard Henderson } 96998cd9ca7SRichard Henderson f = (orig & 4) / 4; 97098cd9ca7SRichard Henderson 971b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 97298cd9ca7SRichard Henderson } 97398cd9ca7SRichard Henderson 97446bb3d46SRichard Henderson /* Similar, but for unit zero conditions. */ 97546bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res) 976b2167459SRichard Henderson { 97746bb3d46SRichard Henderson TCGv_i64 tmp; 978c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 97946bb3d46SRichard Henderson uint64_t ones = 0, sgns = 0; 980b2167459SRichard Henderson 981b2167459SRichard Henderson switch (cf >> 1) { 982578b8132SSven Schnelle case 1: /* SBW / NBW */ 983578b8132SSven Schnelle if (d) { 98446bb3d46SRichard Henderson ones = d_repl; 98546bb3d46SRichard Henderson sgns = d_repl << 31; 986578b8132SSven Schnelle } 987578b8132SSven Schnelle break; 988b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 98946bb3d46SRichard Henderson ones = d_repl * 0x01010101u; 99046bb3d46SRichard Henderson sgns = ones << 7; 99146bb3d46SRichard Henderson break; 99246bb3d46SRichard Henderson case 3: /* SHZ / NHZ */ 99346bb3d46SRichard Henderson ones = d_repl * 0x00010001u; 99446bb3d46SRichard Henderson sgns = ones << 15; 99546bb3d46SRichard Henderson break; 99646bb3d46SRichard Henderson } 99746bb3d46SRichard Henderson if (ones == 0) { 99846bb3d46SRichard Henderson /* Undefined, or 0/1 (never/always). */ 99946bb3d46SRichard Henderson return cf & 1 ? cond_make_t() : cond_make_f(); 100046bb3d46SRichard Henderson } 100146bb3d46SRichard Henderson 100246bb3d46SRichard Henderson /* 100346bb3d46SRichard Henderson * See hasless(v,1) from 1004b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 1005b2167459SRichard Henderson */ 1006aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 100746bb3d46SRichard Henderson tcg_gen_subi_i64(tmp, res, ones); 10086fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 1009b2167459SRichard Henderson 101025f97be7SRichard Henderson return cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE, tmp, sgns); 1011b2167459SRichard Henderson } 1012b2167459SRichard Henderson 10136fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 10146fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 101572ca8753SRichard Henderson { 101682d0c831SRichard Henderson if (!d) { 1017aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 10186fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 101972ca8753SRichard Henderson return t; 102072ca8753SRichard Henderson } 102172ca8753SRichard Henderson return cb_msb; 102272ca8753SRichard Henderson } 102372ca8753SRichard Henderson 10246fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 102572ca8753SRichard Henderson { 102672ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 102772ca8753SRichard Henderson } 102872ca8753SRichard Henderson 1029b2167459SRichard Henderson /* Compute signed overflow for addition. */ 10306fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 1031f8f5986eSRichard Henderson TCGv_i64 in1, TCGv_i64 in2, 1032f8f5986eSRichard Henderson TCGv_i64 orig_in1, int shift, bool d) 1033b2167459SRichard Henderson { 1034aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1035aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1036b2167459SRichard Henderson 10376fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10386fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10396fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 1040b2167459SRichard Henderson 1041f8f5986eSRichard Henderson switch (shift) { 1042f8f5986eSRichard Henderson case 0: 1043f8f5986eSRichard Henderson break; 1044f8f5986eSRichard Henderson case 1: 1045f8f5986eSRichard Henderson /* Shift left by one and compare the sign. */ 1046f8f5986eSRichard Henderson tcg_gen_add_i64(tmp, orig_in1, orig_in1); 1047f8f5986eSRichard Henderson tcg_gen_xor_i64(tmp, tmp, orig_in1); 1048f8f5986eSRichard Henderson /* Incorporate into the overflow. */ 1049f8f5986eSRichard Henderson tcg_gen_or_i64(sv, sv, tmp); 1050f8f5986eSRichard Henderson break; 1051f8f5986eSRichard Henderson default: 1052f8f5986eSRichard Henderson { 1053f8f5986eSRichard Henderson int sign_bit = d ? 63 : 31; 1054f8f5986eSRichard Henderson 1055f8f5986eSRichard Henderson /* Compare the sign against all lower bits. */ 1056f8f5986eSRichard Henderson tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1); 1057f8f5986eSRichard Henderson tcg_gen_xor_i64(tmp, tmp, orig_in1); 1058f8f5986eSRichard Henderson /* 1059f8f5986eSRichard Henderson * If one of the bits shifting into or through the sign 1060f8f5986eSRichard Henderson * differs, then we have overflow. 1061f8f5986eSRichard Henderson */ 1062f8f5986eSRichard Henderson tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift); 1063f8f5986eSRichard Henderson tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero, 1064f8f5986eSRichard Henderson tcg_constant_i64(-1), sv); 1065f8f5986eSRichard Henderson } 1066f8f5986eSRichard Henderson } 1067b2167459SRichard Henderson return sv; 1068b2167459SRichard Henderson } 1069b2167459SRichard Henderson 1070f8f5986eSRichard Henderson /* Compute unsigned overflow for addition. */ 1071f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb, 1072f8f5986eSRichard Henderson TCGv_i64 in1, int shift, bool d) 1073f8f5986eSRichard Henderson { 1074f8f5986eSRichard Henderson if (shift == 0) { 1075f8f5986eSRichard Henderson return get_carry(ctx, d, cb, cb_msb); 1076f8f5986eSRichard Henderson } else { 1077f8f5986eSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1078f8f5986eSRichard Henderson tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift); 1079f8f5986eSRichard Henderson tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb)); 1080f8f5986eSRichard Henderson return tmp; 1081f8f5986eSRichard Henderson } 1082f8f5986eSRichard Henderson } 1083f8f5986eSRichard Henderson 1084b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 10856fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 10866fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1087b2167459SRichard Henderson { 1088aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1089aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1090b2167459SRichard Henderson 10916fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10926fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10936fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 1094b2167459SRichard Henderson 1095b2167459SRichard Henderson return sv; 1096b2167459SRichard Henderson } 1097b2167459SRichard Henderson 1098f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1, 10996fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1100faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1101b2167459SRichard Henderson { 1102f8f5986eSRichard Henderson TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp; 1103b2167459SRichard Henderson unsigned c = cf >> 1; 1104b2167459SRichard Henderson DisasCond cond; 1105b2167459SRichard Henderson 1106aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1107f764718dSRichard Henderson cb = NULL; 1108f764718dSRichard Henderson cb_msb = NULL; 1109b2167459SRichard Henderson 1110f8f5986eSRichard Henderson in1 = orig_in1; 1111b2167459SRichard Henderson if (shift) { 1112aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11136fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1114b2167459SRichard Henderson in1 = tmp; 1115b2167459SRichard Henderson } 1116b2167459SRichard Henderson 1117b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1118aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1119aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1120bdcccc17SRichard Henderson 1121a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1122b2167459SRichard Henderson if (is_c) { 11236fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1124a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1125b2167459SRichard Henderson } 11266fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 11276fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1128b2167459SRichard Henderson } else { 11296fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1130b2167459SRichard Henderson if (is_c) { 11316fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1132b2167459SRichard Henderson } 1133b2167459SRichard Henderson } 1134b2167459SRichard Henderson 1135b2167459SRichard Henderson /* Compute signed overflow if required. */ 1136f764718dSRichard Henderson sv = NULL; 1137b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1138f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d); 1139b2167459SRichard Henderson if (is_tsv) { 1140bd1ad92cSSven Schnelle if (!d) { 1141bd1ad92cSSven Schnelle tcg_gen_ext32s_i64(sv, sv); 1142bd1ad92cSSven Schnelle } 1143ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1144b2167459SRichard Henderson } 1145b2167459SRichard Henderson } 1146b2167459SRichard Henderson 1147f8f5986eSRichard Henderson /* Compute unsigned overflow if required. */ 1148f8f5986eSRichard Henderson uv = NULL; 1149f8f5986eSRichard Henderson if (cond_need_cb(c)) { 1150f8f5986eSRichard Henderson uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d); 1151f8f5986eSRichard Henderson } 1152f8f5986eSRichard Henderson 1153b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1154f8f5986eSRichard Henderson cond = do_cond(ctx, cf, d, dest, uv, sv); 1155b2167459SRichard Henderson if (is_tc) { 1156aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11576fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1158ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1159b2167459SRichard Henderson } 1160b2167459SRichard Henderson 1161b2167459SRichard Henderson /* Write back the result. */ 1162b2167459SRichard Henderson if (!is_l) { 1163b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1164b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1165b2167459SRichard Henderson } 1166b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1167b2167459SRichard Henderson 1168b2167459SRichard Henderson /* Install the new nullification. */ 1169b2167459SRichard Henderson cond_free(&ctx->null_cond); 1170b2167459SRichard Henderson ctx->null_cond = cond; 1171b2167459SRichard Henderson } 1172b2167459SRichard Henderson 1173faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 11740c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 11750c982a28SRichard Henderson { 11766fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 11770c982a28SRichard Henderson 11780c982a28SRichard Henderson if (a->cf) { 11790c982a28SRichard Henderson nullify_over(ctx); 11800c982a28SRichard Henderson } 11810c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 11820c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1183faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1184faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 11850c982a28SRichard Henderson return nullify_end(ctx); 11860c982a28SRichard Henderson } 11870c982a28SRichard Henderson 11880588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 11890588e061SRichard Henderson bool is_tsv, bool is_tc) 11900588e061SRichard Henderson { 11916fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11920588e061SRichard Henderson 11930588e061SRichard Henderson if (a->cf) { 11940588e061SRichard Henderson nullify_over(ctx); 11950588e061SRichard Henderson } 11966fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11970588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1198faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1199faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 12000588e061SRichard Henderson return nullify_end(ctx); 12010588e061SRichard Henderson } 12020588e061SRichard Henderson 12036fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12046fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 120563c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1206b2167459SRichard Henderson { 1207a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1208b2167459SRichard Henderson unsigned c = cf >> 1; 1209b2167459SRichard Henderson DisasCond cond; 1210b2167459SRichard Henderson 1211aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1212aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1213aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1214b2167459SRichard Henderson 1215b2167459SRichard Henderson if (is_b) { 1216b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 12176fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1218a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1219a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1220a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 12216fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 12226fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1223b2167459SRichard Henderson } else { 1224bdcccc17SRichard Henderson /* 1225bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1226bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1227bdcccc17SRichard Henderson */ 12286fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1229a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 12306fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 12316fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1232b2167459SRichard Henderson } 1233b2167459SRichard Henderson 1234b2167459SRichard Henderson /* Compute signed overflow if required. */ 1235f764718dSRichard Henderson sv = NULL; 1236b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1237b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1238b2167459SRichard Henderson if (is_tsv) { 1239bd1ad92cSSven Schnelle if (!d) { 1240bd1ad92cSSven Schnelle tcg_gen_ext32s_i64(sv, sv); 1241bd1ad92cSSven Schnelle } 1242ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1243b2167459SRichard Henderson } 1244b2167459SRichard Henderson } 1245b2167459SRichard Henderson 1246b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1247b2167459SRichard Henderson if (!is_b) { 12484fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1249b2167459SRichard Henderson } else { 1250a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1251b2167459SRichard Henderson } 1252b2167459SRichard Henderson 1253b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1254b2167459SRichard Henderson if (is_tc) { 1255aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 12566fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1257ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1258b2167459SRichard Henderson } 1259b2167459SRichard Henderson 1260b2167459SRichard Henderson /* Write back the result. */ 1261b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1262b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1263b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1264b2167459SRichard Henderson 1265b2167459SRichard Henderson /* Install the new nullification. */ 1266b2167459SRichard Henderson cond_free(&ctx->null_cond); 1267b2167459SRichard Henderson ctx->null_cond = cond; 1268b2167459SRichard Henderson } 1269b2167459SRichard Henderson 127063c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12710c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 12720c982a28SRichard Henderson { 12736fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12740c982a28SRichard Henderson 12750c982a28SRichard Henderson if (a->cf) { 12760c982a28SRichard Henderson nullify_over(ctx); 12770c982a28SRichard Henderson } 12780c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12790c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 128063c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 12810c982a28SRichard Henderson return nullify_end(ctx); 12820c982a28SRichard Henderson } 12830c982a28SRichard Henderson 12840588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 12850588e061SRichard Henderson { 12866fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 12870588e061SRichard Henderson 12880588e061SRichard Henderson if (a->cf) { 12890588e061SRichard Henderson nullify_over(ctx); 12900588e061SRichard Henderson } 12916fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 12920588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 129363c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 129463c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 12950588e061SRichard Henderson return nullify_end(ctx); 12960588e061SRichard Henderson } 12970588e061SRichard Henderson 12986fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12996fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1300b2167459SRichard Henderson { 13016fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1302b2167459SRichard Henderson DisasCond cond; 1303b2167459SRichard Henderson 1304aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 13056fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1306b2167459SRichard Henderson 1307b2167459SRichard Henderson /* Compute signed overflow if required. */ 1308f764718dSRichard Henderson sv = NULL; 1309b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1310b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1311b2167459SRichard Henderson } 1312b2167459SRichard Henderson 1313b2167459SRichard Henderson /* Form the condition for the compare. */ 13144fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1315b2167459SRichard Henderson 1316b2167459SRichard Henderson /* Clear. */ 13176fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1318b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1319b2167459SRichard Henderson 1320b2167459SRichard Henderson /* Install the new nullification. */ 1321b2167459SRichard Henderson cond_free(&ctx->null_cond); 1322b2167459SRichard Henderson ctx->null_cond = cond; 1323b2167459SRichard Henderson } 1324b2167459SRichard Henderson 13256fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 13266fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 13276fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1328b2167459SRichard Henderson { 13296fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1330b2167459SRichard Henderson 1331b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1332b2167459SRichard Henderson fn(dest, in1, in2); 1333b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1334b2167459SRichard Henderson 1335b2167459SRichard Henderson /* Install the new nullification. */ 1336b2167459SRichard Henderson cond_free(&ctx->null_cond); 1337b2167459SRichard Henderson if (cf) { 1338b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1339b2167459SRichard Henderson } 1340b2167459SRichard Henderson } 1341b2167459SRichard Henderson 1342fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 13436fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 13440c982a28SRichard Henderson { 13456fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 13460c982a28SRichard Henderson 13470c982a28SRichard Henderson if (a->cf) { 13480c982a28SRichard Henderson nullify_over(ctx); 13490c982a28SRichard Henderson } 13500c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 13510c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1352fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 13530c982a28SRichard Henderson return nullify_end(ctx); 13540c982a28SRichard Henderson } 13550c982a28SRichard Henderson 135646bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 135746bb3d46SRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 135846bb3d46SRichard Henderson bool is_tc, bool is_add) 1359b2167459SRichard Henderson { 136046bb3d46SRichard Henderson TCGv_i64 dest = tcg_temp_new_i64(); 136146bb3d46SRichard Henderson uint64_t test_cb = 0; 1362b2167459SRichard Henderson DisasCond cond; 1363b2167459SRichard Henderson 136446bb3d46SRichard Henderson /* Select which carry-out bits to test. */ 136546bb3d46SRichard Henderson switch (cf >> 1) { 136646bb3d46SRichard Henderson case 4: /* NDC / SDC -- 4-bit carries */ 136746bb3d46SRichard Henderson test_cb = dup_const(MO_8, 0x88); 136846bb3d46SRichard Henderson break; 136946bb3d46SRichard Henderson case 5: /* NWC / SWC -- 32-bit carries */ 137046bb3d46SRichard Henderson if (d) { 137146bb3d46SRichard Henderson test_cb = dup_const(MO_32, INT32_MIN); 1372b2167459SRichard Henderson } else { 137346bb3d46SRichard Henderson cf &= 1; /* undefined -- map to never/always */ 137446bb3d46SRichard Henderson } 137546bb3d46SRichard Henderson break; 137646bb3d46SRichard Henderson case 6: /* NBC / SBC -- 8-bit carries */ 137746bb3d46SRichard Henderson test_cb = dup_const(MO_8, INT8_MIN); 137846bb3d46SRichard Henderson break; 137946bb3d46SRichard Henderson case 7: /* NHC / SHC -- 16-bit carries */ 138046bb3d46SRichard Henderson test_cb = dup_const(MO_16, INT16_MIN); 138146bb3d46SRichard Henderson break; 138246bb3d46SRichard Henderson } 138346bb3d46SRichard Henderson if (!d) { 138446bb3d46SRichard Henderson test_cb = (uint32_t)test_cb; 138546bb3d46SRichard Henderson } 1386b2167459SRichard Henderson 138746bb3d46SRichard Henderson if (!test_cb) { 138846bb3d46SRichard Henderson /* No need to compute carries if we don't need to test them. */ 138946bb3d46SRichard Henderson if (is_add) { 139046bb3d46SRichard Henderson tcg_gen_add_i64(dest, in1, in2); 139146bb3d46SRichard Henderson } else { 139246bb3d46SRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 139346bb3d46SRichard Henderson } 139446bb3d46SRichard Henderson cond = do_unit_zero_cond(cf, d, dest); 139546bb3d46SRichard Henderson } else { 139646bb3d46SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 139746bb3d46SRichard Henderson 139846bb3d46SRichard Henderson if (d) { 139946bb3d46SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 140046bb3d46SRichard Henderson if (is_add) { 140146bb3d46SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 140246bb3d46SRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 140346bb3d46SRichard Henderson } else { 140446bb3d46SRichard Henderson /* See do_sub, !is_b. */ 140546bb3d46SRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 140646bb3d46SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 140746bb3d46SRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 140846bb3d46SRichard Henderson } 140946bb3d46SRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 141046bb3d46SRichard Henderson tcg_gen_extract2_i64(cb, cb, cb_msb, 1); 141146bb3d46SRichard Henderson } else { 141246bb3d46SRichard Henderson if (is_add) { 141346bb3d46SRichard Henderson tcg_gen_add_i64(dest, in1, in2); 141446bb3d46SRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 141546bb3d46SRichard Henderson } else { 141646bb3d46SRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 141746bb3d46SRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 141846bb3d46SRichard Henderson } 141946bb3d46SRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 142046bb3d46SRichard Henderson tcg_gen_shri_i64(cb, cb, 1); 142146bb3d46SRichard Henderson } 142246bb3d46SRichard Henderson 14233289ea0eSRichard Henderson cond = cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE, 14243289ea0eSRichard Henderson cb, test_cb); 142546bb3d46SRichard Henderson } 1426b2167459SRichard Henderson 1427b2167459SRichard Henderson if (is_tc) { 1428aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 14296fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1430ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1431b2167459SRichard Henderson } 1432b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1433b2167459SRichard Henderson 1434b2167459SRichard Henderson cond_free(&ctx->null_cond); 1435b2167459SRichard Henderson ctx->null_cond = cond; 1436b2167459SRichard Henderson } 1437b2167459SRichard Henderson 143886f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 14398d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 14408d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 14418d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 14428d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 14436fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 144486f8d05fSRichard Henderson { 144586f8d05fSRichard Henderson TCGv_ptr ptr; 14466fd0c7bcSRichard Henderson TCGv_i64 tmp; 144786f8d05fSRichard Henderson TCGv_i64 spc; 144886f8d05fSRichard Henderson 144986f8d05fSRichard Henderson if (sp != 0) { 14508d6ae7fbSRichard Henderson if (sp < 0) { 14518d6ae7fbSRichard Henderson sp = ~sp; 14528d6ae7fbSRichard Henderson } 14536fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 14548d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 14558d6ae7fbSRichard Henderson return spc; 145686f8d05fSRichard Henderson } 1457494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1458494737b7SRichard Henderson return cpu_srH; 1459494737b7SRichard Henderson } 146086f8d05fSRichard Henderson 146186f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1462aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 14636fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 146486f8d05fSRichard Henderson 1465698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 14666fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 14676fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 14686fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 146986f8d05fSRichard Henderson 1470ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 147186f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 147286f8d05fSRichard Henderson 147386f8d05fSRichard Henderson return spc; 147486f8d05fSRichard Henderson } 147586f8d05fSRichard Henderson #endif 147686f8d05fSRichard Henderson 14776fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1478c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 147986f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 148086f8d05fSRichard Henderson { 14816fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 14826fd0c7bcSRichard Henderson TCGv_i64 ofs; 14836fd0c7bcSRichard Henderson TCGv_i64 addr; 148486f8d05fSRichard Henderson 1485f5b5c857SRichard Henderson set_insn_breg(ctx, rb); 1486f5b5c857SRichard Henderson 148786f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 148886f8d05fSRichard Henderson if (rx) { 1489aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 14906fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 14916fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 149286f8d05fSRichard Henderson } else if (disp || modify) { 1493aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 14946fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 149586f8d05fSRichard Henderson } else { 149686f8d05fSRichard Henderson ofs = base; 149786f8d05fSRichard Henderson } 149886f8d05fSRichard Henderson 149986f8d05fSRichard Henderson *pofs = ofs; 15006fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 15017d50b696SSven Schnelle tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, 15027d50b696SSven Schnelle gva_offset_mask(ctx->tb_flags)); 1503698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 150486f8d05fSRichard Henderson if (!is_phys) { 1505d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 150686f8d05fSRichard Henderson } 150786f8d05fSRichard Henderson #endif 150886f8d05fSRichard Henderson } 150986f8d05fSRichard Henderson 151096d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 151196d6407fSRichard Henderson * < 0 for pre-modify, 151296d6407fSRichard Henderson * > 0 for post-modify, 151396d6407fSRichard Henderson * = 0 for no base register update. 151496d6407fSRichard Henderson */ 151596d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1516c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 151714776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 151896d6407fSRichard Henderson { 15196fd0c7bcSRichard Henderson TCGv_i64 ofs; 15206fd0c7bcSRichard Henderson TCGv_i64 addr; 152196d6407fSRichard Henderson 152296d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 152396d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 152496d6407fSRichard Henderson 152586f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 152617fe594cSRichard Henderson MMU_DISABLED(ctx)); 1527c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 152886f8d05fSRichard Henderson if (modify) { 152986f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 153096d6407fSRichard Henderson } 153196d6407fSRichard Henderson } 153296d6407fSRichard Henderson 153396d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1534c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 153514776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 153696d6407fSRichard Henderson { 15376fd0c7bcSRichard Henderson TCGv_i64 ofs; 15386fd0c7bcSRichard Henderson TCGv_i64 addr; 153996d6407fSRichard Henderson 154096d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 154196d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 154296d6407fSRichard Henderson 154386f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 154417fe594cSRichard Henderson MMU_DISABLED(ctx)); 1545217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 154686f8d05fSRichard Henderson if (modify) { 154786f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 154896d6407fSRichard Henderson } 154996d6407fSRichard Henderson } 155096d6407fSRichard Henderson 155196d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1552c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 155314776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 155496d6407fSRichard Henderson { 15556fd0c7bcSRichard Henderson TCGv_i64 ofs; 15566fd0c7bcSRichard Henderson TCGv_i64 addr; 155796d6407fSRichard Henderson 155896d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 155996d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 156096d6407fSRichard Henderson 156186f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 156217fe594cSRichard Henderson MMU_DISABLED(ctx)); 1563217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 156486f8d05fSRichard Henderson if (modify) { 156586f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 156696d6407fSRichard Henderson } 156796d6407fSRichard Henderson } 156896d6407fSRichard Henderson 156996d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1570c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 157114776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 157296d6407fSRichard Henderson { 15736fd0c7bcSRichard Henderson TCGv_i64 ofs; 15746fd0c7bcSRichard Henderson TCGv_i64 addr; 157596d6407fSRichard Henderson 157696d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 157796d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 157896d6407fSRichard Henderson 157986f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 158017fe594cSRichard Henderson MMU_DISABLED(ctx)); 1581217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 158286f8d05fSRichard Henderson if (modify) { 158386f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 158496d6407fSRichard Henderson } 158596d6407fSRichard Henderson } 158696d6407fSRichard Henderson 15871cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1588c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 158914776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 159096d6407fSRichard Henderson { 15916fd0c7bcSRichard Henderson TCGv_i64 dest; 159296d6407fSRichard Henderson 159396d6407fSRichard Henderson nullify_over(ctx); 159496d6407fSRichard Henderson 159596d6407fSRichard Henderson if (modify == 0) { 159696d6407fSRichard Henderson /* No base register update. */ 159796d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 159896d6407fSRichard Henderson } else { 159996d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1600aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 160196d6407fSRichard Henderson } 16026fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 160396d6407fSRichard Henderson save_gpr(ctx, rt, dest); 160496d6407fSRichard Henderson 16051cd012a5SRichard Henderson return nullify_end(ctx); 160696d6407fSRichard Henderson } 160796d6407fSRichard Henderson 1608740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1609c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 161086f8d05fSRichard Henderson unsigned sp, int modify) 161196d6407fSRichard Henderson { 161296d6407fSRichard Henderson TCGv_i32 tmp; 161396d6407fSRichard Henderson 161496d6407fSRichard Henderson nullify_over(ctx); 161596d6407fSRichard Henderson 161696d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 161786f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 161896d6407fSRichard Henderson save_frw_i32(rt, tmp); 161996d6407fSRichard Henderson 162096d6407fSRichard Henderson if (rt == 0) { 1621ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 162296d6407fSRichard Henderson } 162396d6407fSRichard Henderson 1624740038d7SRichard Henderson return nullify_end(ctx); 162596d6407fSRichard Henderson } 162696d6407fSRichard Henderson 1627740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1628740038d7SRichard Henderson { 1629740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1630740038d7SRichard Henderson a->disp, a->sp, a->m); 1631740038d7SRichard Henderson } 1632740038d7SRichard Henderson 1633740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1634c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 163586f8d05fSRichard Henderson unsigned sp, int modify) 163696d6407fSRichard Henderson { 163796d6407fSRichard Henderson TCGv_i64 tmp; 163896d6407fSRichard Henderson 163996d6407fSRichard Henderson nullify_over(ctx); 164096d6407fSRichard Henderson 164196d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1642fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 164396d6407fSRichard Henderson save_frd(rt, tmp); 164496d6407fSRichard Henderson 164596d6407fSRichard Henderson if (rt == 0) { 1646ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 164796d6407fSRichard Henderson } 164896d6407fSRichard Henderson 1649740038d7SRichard Henderson return nullify_end(ctx); 1650740038d7SRichard Henderson } 1651740038d7SRichard Henderson 1652740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1653740038d7SRichard Henderson { 1654740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1655740038d7SRichard Henderson a->disp, a->sp, a->m); 165696d6407fSRichard Henderson } 165796d6407fSRichard Henderson 16581cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1659c53e401eSRichard Henderson int64_t disp, unsigned sp, 166014776ab5STony Nguyen int modify, MemOp mop) 166196d6407fSRichard Henderson { 166296d6407fSRichard Henderson nullify_over(ctx); 16636fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 16641cd012a5SRichard Henderson return nullify_end(ctx); 166596d6407fSRichard Henderson } 166696d6407fSRichard Henderson 1667740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1668c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 166986f8d05fSRichard Henderson unsigned sp, int modify) 167096d6407fSRichard Henderson { 167196d6407fSRichard Henderson TCGv_i32 tmp; 167296d6407fSRichard Henderson 167396d6407fSRichard Henderson nullify_over(ctx); 167496d6407fSRichard Henderson 167596d6407fSRichard Henderson tmp = load_frw_i32(rt); 167686f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 167796d6407fSRichard Henderson 1678740038d7SRichard Henderson return nullify_end(ctx); 167996d6407fSRichard Henderson } 168096d6407fSRichard Henderson 1681740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1682740038d7SRichard Henderson { 1683740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1684740038d7SRichard Henderson a->disp, a->sp, a->m); 1685740038d7SRichard Henderson } 1686740038d7SRichard Henderson 1687740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1688c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 168986f8d05fSRichard Henderson unsigned sp, int modify) 169096d6407fSRichard Henderson { 169196d6407fSRichard Henderson TCGv_i64 tmp; 169296d6407fSRichard Henderson 169396d6407fSRichard Henderson nullify_over(ctx); 169496d6407fSRichard Henderson 169596d6407fSRichard Henderson tmp = load_frd(rt); 1696fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 169796d6407fSRichard Henderson 1698740038d7SRichard Henderson return nullify_end(ctx); 1699740038d7SRichard Henderson } 1700740038d7SRichard Henderson 1701740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1702740038d7SRichard Henderson { 1703740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1704740038d7SRichard Henderson a->disp, a->sp, a->m); 170596d6407fSRichard Henderson } 170696d6407fSRichard Henderson 17071ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1708ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1709ebe9383cSRichard Henderson { 1710ebe9383cSRichard Henderson TCGv_i32 tmp; 1711ebe9383cSRichard Henderson 1712ebe9383cSRichard Henderson nullify_over(ctx); 1713ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1714ebe9383cSRichard Henderson 1715ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1716ebe9383cSRichard Henderson 1717ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 17181ca74648SRichard Henderson return nullify_end(ctx); 1719ebe9383cSRichard Henderson } 1720ebe9383cSRichard Henderson 17211ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1722ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1723ebe9383cSRichard Henderson { 1724ebe9383cSRichard Henderson TCGv_i32 dst; 1725ebe9383cSRichard Henderson TCGv_i64 src; 1726ebe9383cSRichard Henderson 1727ebe9383cSRichard Henderson nullify_over(ctx); 1728ebe9383cSRichard Henderson src = load_frd(ra); 1729ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1730ebe9383cSRichard Henderson 1731ad75a51eSRichard Henderson func(dst, tcg_env, src); 1732ebe9383cSRichard Henderson 1733ebe9383cSRichard Henderson save_frw_i32(rt, dst); 17341ca74648SRichard Henderson return nullify_end(ctx); 1735ebe9383cSRichard Henderson } 1736ebe9383cSRichard Henderson 17371ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1738ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1739ebe9383cSRichard Henderson { 1740ebe9383cSRichard Henderson TCGv_i64 tmp; 1741ebe9383cSRichard Henderson 1742ebe9383cSRichard Henderson nullify_over(ctx); 1743ebe9383cSRichard Henderson tmp = load_frd0(ra); 1744ebe9383cSRichard Henderson 1745ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1746ebe9383cSRichard Henderson 1747ebe9383cSRichard Henderson save_frd(rt, tmp); 17481ca74648SRichard Henderson return nullify_end(ctx); 1749ebe9383cSRichard Henderson } 1750ebe9383cSRichard Henderson 17511ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1752ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1753ebe9383cSRichard Henderson { 1754ebe9383cSRichard Henderson TCGv_i32 src; 1755ebe9383cSRichard Henderson TCGv_i64 dst; 1756ebe9383cSRichard Henderson 1757ebe9383cSRichard Henderson nullify_over(ctx); 1758ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1759ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1760ebe9383cSRichard Henderson 1761ad75a51eSRichard Henderson func(dst, tcg_env, src); 1762ebe9383cSRichard Henderson 1763ebe9383cSRichard Henderson save_frd(rt, dst); 17641ca74648SRichard Henderson return nullify_end(ctx); 1765ebe9383cSRichard Henderson } 1766ebe9383cSRichard Henderson 17671ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1768ebe9383cSRichard Henderson unsigned ra, unsigned rb, 176931234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1770ebe9383cSRichard Henderson { 1771ebe9383cSRichard Henderson TCGv_i32 a, b; 1772ebe9383cSRichard Henderson 1773ebe9383cSRichard Henderson nullify_over(ctx); 1774ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1775ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1776ebe9383cSRichard Henderson 1777ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1778ebe9383cSRichard Henderson 1779ebe9383cSRichard Henderson save_frw_i32(rt, a); 17801ca74648SRichard Henderson return nullify_end(ctx); 1781ebe9383cSRichard Henderson } 1782ebe9383cSRichard Henderson 17831ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1784ebe9383cSRichard Henderson unsigned ra, unsigned rb, 178531234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1786ebe9383cSRichard Henderson { 1787ebe9383cSRichard Henderson TCGv_i64 a, b; 1788ebe9383cSRichard Henderson 1789ebe9383cSRichard Henderson nullify_over(ctx); 1790ebe9383cSRichard Henderson a = load_frd0(ra); 1791ebe9383cSRichard Henderson b = load_frd0(rb); 1792ebe9383cSRichard Henderson 1793ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1794ebe9383cSRichard Henderson 1795ebe9383cSRichard Henderson save_frd(rt, a); 17961ca74648SRichard Henderson return nullify_end(ctx); 1797ebe9383cSRichard Henderson } 1798ebe9383cSRichard Henderson 179998cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 180098cd9ca7SRichard Henderson have already had nullification handled. */ 18012644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp, 180298cd9ca7SRichard Henderson unsigned link, bool is_n) 180398cd9ca7SRichard Henderson { 1804bc921866SRichard Henderson ctx->iaq_j = iaqe_branchi(ctx, disp); 18052644f80bSRichard Henderson 180698cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 180743541db0SRichard Henderson install_link(ctx, link, false); 180898cd9ca7SRichard Henderson if (is_n) { 1809d08ad0e0SRichard Henderson if (use_nullify_skip(ctx)) { 1810d08ad0e0SRichard Henderson nullify_set(ctx, 0); 1811bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL); 1812d08ad0e0SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 1813d08ad0e0SRichard Henderson return true; 1814d08ad0e0SRichard Henderson } 181598cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 181698cd9ca7SRichard Henderson } 1817bc921866SRichard Henderson ctx->iaq_n = &ctx->iaq_j; 181898cd9ca7SRichard Henderson } else { 181998cd9ca7SRichard Henderson nullify_over(ctx); 182098cd9ca7SRichard Henderson 182143541db0SRichard Henderson install_link(ctx, link, false); 182298cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 182398cd9ca7SRichard Henderson nullify_set(ctx, 0); 1824bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL); 182598cd9ca7SRichard Henderson } else { 182698cd9ca7SRichard Henderson nullify_set(ctx, is_n); 1827bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_b, &ctx->iaq_j); 182898cd9ca7SRichard Henderson } 182931234768SRichard Henderson nullify_end(ctx); 183098cd9ca7SRichard Henderson 183198cd9ca7SRichard Henderson nullify_set(ctx, 0); 1832bc921866SRichard Henderson gen_goto_tb(ctx, 1, &ctx->iaq_b, NULL); 183331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 183498cd9ca7SRichard Henderson } 183501afb7beSRichard Henderson return true; 183698cd9ca7SRichard Henderson } 183798cd9ca7SRichard Henderson 183898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 183998cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1840c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 184198cd9ca7SRichard Henderson DisasCond *cond) 184298cd9ca7SRichard Henderson { 1843bc921866SRichard Henderson DisasIAQE next; 184498cd9ca7SRichard Henderson TCGLabel *taken = NULL; 184598cd9ca7SRichard Henderson TCGCond c = cond->c; 184698cd9ca7SRichard Henderson bool n; 184798cd9ca7SRichard Henderson 184898cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 184998cd9ca7SRichard Henderson 185098cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 185198cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 18522644f80bSRichard Henderson return do_dbranch(ctx, disp, 0, is_n && disp >= 0); 185398cd9ca7SRichard Henderson } 185498cd9ca7SRichard Henderson 185598cd9ca7SRichard Henderson taken = gen_new_label(); 18566fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 185798cd9ca7SRichard Henderson cond_free(cond); 185898cd9ca7SRichard Henderson 185998cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 186098cd9ca7SRichard Henderson n = is_n && disp < 0; 186198cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 186298cd9ca7SRichard Henderson nullify_set(ctx, 0); 1863bc921866SRichard Henderson next = iaqe_incr(&ctx->iaq_b, 4); 1864bc921866SRichard Henderson gen_goto_tb(ctx, 0, &next, NULL); 186598cd9ca7SRichard Henderson } else { 186698cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 186798cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 186898cd9ca7SRichard Henderson ctx->null_lab = NULL; 186998cd9ca7SRichard Henderson } 187098cd9ca7SRichard Henderson nullify_set(ctx, n); 1871bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_b, NULL); 187298cd9ca7SRichard Henderson } 187398cd9ca7SRichard Henderson 187498cd9ca7SRichard Henderson gen_set_label(taken); 187598cd9ca7SRichard Henderson 187698cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 187798cd9ca7SRichard Henderson n = is_n && disp >= 0; 1878bc921866SRichard Henderson 1879bc921866SRichard Henderson next = iaqe_branchi(ctx, disp); 188098cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 188198cd9ca7SRichard Henderson nullify_set(ctx, 0); 1882bc921866SRichard Henderson gen_goto_tb(ctx, 1, &next, NULL); 188398cd9ca7SRichard Henderson } else { 188498cd9ca7SRichard Henderson nullify_set(ctx, n); 1885bc921866SRichard Henderson gen_goto_tb(ctx, 1, &ctx->iaq_b, &next); 188698cd9ca7SRichard Henderson } 188798cd9ca7SRichard Henderson 188898cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 188998cd9ca7SRichard Henderson if (ctx->null_lab) { 189098cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 189198cd9ca7SRichard Henderson ctx->null_lab = NULL; 189231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 189398cd9ca7SRichard Henderson } else { 189431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 189598cd9ca7SRichard Henderson } 189601afb7beSRichard Henderson return true; 189798cd9ca7SRichard Henderson } 189898cd9ca7SRichard Henderson 1899bc921866SRichard Henderson /* 1900bc921866SRichard Henderson * Emit an unconditional branch to an indirect target, in ctx->iaq_j. 1901bc921866SRichard Henderson * This handles nullification of the branch itself. 1902bc921866SRichard Henderson */ 1903bc921866SRichard Henderson static bool do_ibranch(DisasContext *ctx, unsigned link, 1904bc921866SRichard Henderson bool with_sr0, bool is_n) 190598cd9ca7SRichard Henderson { 1906d582c1faSRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 1907019f4159SRichard Henderson install_link(ctx, link, with_sr0); 190898cd9ca7SRichard Henderson if (is_n) { 1909c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1910bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_j, NULL); 1911c301f34eSRichard Henderson nullify_set(ctx, 0); 191231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 191301afb7beSRichard Henderson return true; 1914c301f34eSRichard Henderson } 191598cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 191698cd9ca7SRichard Henderson } 1917bc921866SRichard Henderson ctx->iaq_n = &ctx->iaq_j; 1918d582c1faSRichard Henderson return true; 1919d582c1faSRichard Henderson } 192098cd9ca7SRichard Henderson 1921d582c1faSRichard Henderson nullify_over(ctx); 1922d582c1faSRichard Henderson 1923019f4159SRichard Henderson install_link(ctx, link, with_sr0); 1924d582c1faSRichard Henderson if (is_n && use_nullify_skip(ctx)) { 1925bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_j, NULL); 1926d582c1faSRichard Henderson nullify_set(ctx, 0); 1927d582c1faSRichard Henderson } else { 1928bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j); 1929d582c1faSRichard Henderson nullify_set(ctx, is_n); 1930d582c1faSRichard Henderson } 1931d582c1faSRichard Henderson 19327f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 1933d582c1faSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 193401afb7beSRichard Henderson return nullify_end(ctx); 193598cd9ca7SRichard Henderson } 193698cd9ca7SRichard Henderson 1937660eefe1SRichard Henderson /* Implement 1938660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1939660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1940660eefe1SRichard Henderson * else 1941660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1942660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1943660eefe1SRichard Henderson */ 19446fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1945660eefe1SRichard Henderson { 19461874e6c2SRichard Henderson TCGv_i64 dest = tcg_temp_new_i64(); 1947660eefe1SRichard Henderson switch (ctx->privilege) { 1948660eefe1SRichard Henderson case 0: 1949660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 19501874e6c2SRichard Henderson tcg_gen_mov_i64(dest, offset); 19511874e6c2SRichard Henderson break; 1952660eefe1SRichard Henderson case 3: 1953993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 19546fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1955660eefe1SRichard Henderson break; 1956660eefe1SRichard Henderson default: 19576fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 19586fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 19590bb02029SRichard Henderson tcg_gen_umax_i64(dest, dest, offset); 1960660eefe1SRichard Henderson break; 1961660eefe1SRichard Henderson } 1962660eefe1SRichard Henderson return dest; 1963660eefe1SRichard Henderson } 1964660eefe1SRichard Henderson 1965ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 19667ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 19677ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 19687ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 19697ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 19707ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 19717ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 19727ad439dfSRichard Henderson aforementioned BE. */ 197331234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 19747ad439dfSRichard Henderson { 19750d89cb7cSRichard Henderson assert(ctx->iaq_f.disp == 0); 19760d89cb7cSRichard Henderson 19777ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 19787ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 19798b81968cSMichael Tokarev next insn within the privileged page. */ 19807ad439dfSRichard Henderson switch (ctx->null_cond.c) { 19817ad439dfSRichard Henderson case TCG_COND_NEVER: 19827ad439dfSRichard Henderson break; 19837ad439dfSRichard Henderson case TCG_COND_ALWAYS: 19846fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 19857ad439dfSRichard Henderson goto do_sigill; 19867ad439dfSRichard Henderson default: 19877ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 19887ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 19897ad439dfSRichard Henderson g_assert_not_reached(); 19907ad439dfSRichard Henderson } 19917ad439dfSRichard Henderson 19927ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 19937ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 19947ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 19957ad439dfSRichard Henderson under such conditions. */ 19960d89cb7cSRichard Henderson if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != 4) { 19977ad439dfSRichard Henderson goto do_sigill; 19987ad439dfSRichard Henderson } 19997ad439dfSRichard Henderson 20000d89cb7cSRichard Henderson switch (ctx->base.pc_first) { 20017ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 20022986721dSRichard Henderson gen_excp_1(EXCP_IMP); 200331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 200431234768SRichard Henderson break; 20057ad439dfSRichard Henderson 20067ad439dfSRichard Henderson case 0xb0: /* LWS */ 20077ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 200831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 200931234768SRichard Henderson break; 20107ad439dfSRichard Henderson 20117ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 2012bc921866SRichard Henderson { 2013bc921866SRichard Henderson DisasIAQE next = { .base = tcg_temp_new_i64() }; 2014bc921866SRichard Henderson 2015bc921866SRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, 2016bc921866SRichard Henderson offsetof(CPUHPPAState, cr[27])); 2017bc921866SRichard Henderson tcg_gen_ori_i64(next.base, cpu_gr[31], 3); 2018bc921866SRichard Henderson install_iaq_entries(ctx, &next, NULL); 201931234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 2020bc921866SRichard Henderson } 202131234768SRichard Henderson break; 20227ad439dfSRichard Henderson 20237ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 20247ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 202531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 202631234768SRichard Henderson break; 20277ad439dfSRichard Henderson 20287ad439dfSRichard Henderson default: 20297ad439dfSRichard Henderson do_sigill: 20302986721dSRichard Henderson gen_excp_1(EXCP_ILL); 203131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 203231234768SRichard Henderson break; 20337ad439dfSRichard Henderson } 20347ad439dfSRichard Henderson } 2035ba1d0b44SRichard Henderson #endif 20367ad439dfSRichard Henderson 2037deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 2038b2167459SRichard Henderson { 2039b2167459SRichard Henderson cond_free(&ctx->null_cond); 204031234768SRichard Henderson return true; 2041b2167459SRichard Henderson } 2042b2167459SRichard Henderson 204340f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 204498a9cb79SRichard Henderson { 204531234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 204698a9cb79SRichard Henderson } 204798a9cb79SRichard Henderson 2048e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 204998a9cb79SRichard Henderson { 205098a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 205198a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 205298a9cb79SRichard Henderson 205398a9cb79SRichard Henderson cond_free(&ctx->null_cond); 205431234768SRichard Henderson return true; 205598a9cb79SRichard Henderson } 205698a9cb79SRichard Henderson 2057c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 205898a9cb79SRichard Henderson { 2059bc921866SRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 206098a9cb79SRichard Henderson 2061bc921866SRichard Henderson copy_iaoq_entry(ctx, dest, &ctx->iaq_f); 2062bc921866SRichard Henderson tcg_gen_andi_i64(dest, dest, -4); 2063bc921866SRichard Henderson 2064bc921866SRichard Henderson save_gpr(ctx, a->t, dest); 206598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 206631234768SRichard Henderson return true; 206798a9cb79SRichard Henderson } 206898a9cb79SRichard Henderson 2069c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 207098a9cb79SRichard Henderson { 2071c603e14aSRichard Henderson unsigned rt = a->t; 2072c603e14aSRichard Henderson unsigned rs = a->sp; 207333423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 207498a9cb79SRichard Henderson 207533423472SRichard Henderson load_spr(ctx, t0, rs); 207633423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 207733423472SRichard Henderson 2078967662cdSRichard Henderson save_gpr(ctx, rt, t0); 207998a9cb79SRichard Henderson 208098a9cb79SRichard Henderson cond_free(&ctx->null_cond); 208131234768SRichard Henderson return true; 208298a9cb79SRichard Henderson } 208398a9cb79SRichard Henderson 2084c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 208598a9cb79SRichard Henderson { 2086c603e14aSRichard Henderson unsigned rt = a->t; 2087c603e14aSRichard Henderson unsigned ctl = a->r; 20886fd0c7bcSRichard Henderson TCGv_i64 tmp; 208998a9cb79SRichard Henderson 209098a9cb79SRichard Henderson switch (ctl) { 209135136a77SRichard Henderson case CR_SAR: 2092c603e14aSRichard Henderson if (a->e == 0) { 209398a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 209498a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 20956fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 209698a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 209735136a77SRichard Henderson goto done; 209898a9cb79SRichard Henderson } 209998a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 210035136a77SRichard Henderson goto done; 210135136a77SRichard Henderson case CR_IT: /* Interval Timer */ 210235136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 210335136a77SRichard Henderson nullify_over(ctx); 210498a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2105dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 210631234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 210749c29d6cSRichard Henderson } 21080c58c1bcSRichard Henderson gen_helper_read_interval_timer(tmp); 210998a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 211031234768SRichard Henderson return nullify_end(ctx); 211198a9cb79SRichard Henderson case 26: 211298a9cb79SRichard Henderson case 27: 211398a9cb79SRichard Henderson break; 211498a9cb79SRichard Henderson default: 211598a9cb79SRichard Henderson /* All other control registers are privileged. */ 211635136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 211735136a77SRichard Henderson break; 211898a9cb79SRichard Henderson } 211998a9cb79SRichard Henderson 2120aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21216fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 212235136a77SRichard Henderson save_gpr(ctx, rt, tmp); 212335136a77SRichard Henderson 212435136a77SRichard Henderson done: 212598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 212631234768SRichard Henderson return true; 212798a9cb79SRichard Henderson } 212898a9cb79SRichard Henderson 2129c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 213033423472SRichard Henderson { 2131c603e14aSRichard Henderson unsigned rr = a->r; 2132c603e14aSRichard Henderson unsigned rs = a->sp; 2133967662cdSRichard Henderson TCGv_i64 tmp; 213433423472SRichard Henderson 213533423472SRichard Henderson if (rs >= 5) { 213633423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 213733423472SRichard Henderson } 213833423472SRichard Henderson nullify_over(ctx); 213933423472SRichard Henderson 2140967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2141967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 214233423472SRichard Henderson 214333423472SRichard Henderson if (rs >= 4) { 2144967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2145494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 214633423472SRichard Henderson } else { 2147967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 214833423472SRichard Henderson } 214933423472SRichard Henderson 215031234768SRichard Henderson return nullify_end(ctx); 215133423472SRichard Henderson } 215233423472SRichard Henderson 2153c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 215498a9cb79SRichard Henderson { 2155c603e14aSRichard Henderson unsigned ctl = a->t; 21566fd0c7bcSRichard Henderson TCGv_i64 reg; 21576fd0c7bcSRichard Henderson TCGv_i64 tmp; 215898a9cb79SRichard Henderson 215935136a77SRichard Henderson if (ctl == CR_SAR) { 21604845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2161aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21626fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 216398a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 216498a9cb79SRichard Henderson 216598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 216631234768SRichard Henderson return true; 216798a9cb79SRichard Henderson } 216898a9cb79SRichard Henderson 216935136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 217035136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 217135136a77SRichard Henderson 2172c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 217335136a77SRichard Henderson nullify_over(ctx); 21744c34bab0SHelge Deller 21754c34bab0SHelge Deller if (ctx->is_pa20) { 21764845f015SSven Schnelle reg = load_gpr(ctx, a->r); 21774c34bab0SHelge Deller } else { 21784c34bab0SHelge Deller reg = tcg_temp_new_i64(); 21794c34bab0SHelge Deller tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 21804c34bab0SHelge Deller } 21814845f015SSven Schnelle 218235136a77SRichard Henderson switch (ctl) { 218335136a77SRichard Henderson case CR_IT: 2184104281c1SRichard Henderson if (translator_io_start(&ctx->base)) { 2185104281c1SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2186104281c1SRichard Henderson } 2187ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 218835136a77SRichard Henderson break; 21894f5f2548SRichard Henderson case CR_EIRR: 21906ebebea7SRichard Henderson /* Helper modifies interrupt lines and is therefore IO. */ 21916ebebea7SRichard Henderson translator_io_start(&ctx->base); 2192ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 21936ebebea7SRichard Henderson /* Exit to re-evaluate interrupts in the main loop. */ 219431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 21954f5f2548SRichard Henderson break; 21964f5f2548SRichard Henderson 219735136a77SRichard Henderson case CR_IIASQ: 219835136a77SRichard Henderson case CR_IIAOQ: 219935136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 220035136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2201aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22026fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 220335136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 22046fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 22056fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 220635136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 220735136a77SRichard Henderson break; 220835136a77SRichard Henderson 2209d5de20bdSSven Schnelle case CR_PID1: 2210d5de20bdSSven Schnelle case CR_PID2: 2211d5de20bdSSven Schnelle case CR_PID3: 2212d5de20bdSSven Schnelle case CR_PID4: 22136fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2214d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2215ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2216d5de20bdSSven Schnelle #endif 2217d5de20bdSSven Schnelle break; 2218d5de20bdSSven Schnelle 22196ebebea7SRichard Henderson case CR_EIEM: 22206ebebea7SRichard Henderson /* Exit to re-evaluate interrupts in the main loop. */ 22216ebebea7SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 22226ebebea7SRichard Henderson /* FALLTHRU */ 222335136a77SRichard Henderson default: 22246fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 222535136a77SRichard Henderson break; 222635136a77SRichard Henderson } 222731234768SRichard Henderson return nullify_end(ctx); 22284f5f2548SRichard Henderson #endif 222935136a77SRichard Henderson } 223035136a77SRichard Henderson 2231c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 223298a9cb79SRichard Henderson { 2233aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 223498a9cb79SRichard Henderson 22356fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 22366fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 223798a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 223898a9cb79SRichard Henderson 223998a9cb79SRichard Henderson cond_free(&ctx->null_cond); 224031234768SRichard Henderson return true; 224198a9cb79SRichard Henderson } 224298a9cb79SRichard Henderson 2243e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 224498a9cb79SRichard Henderson { 22456fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 224698a9cb79SRichard Henderson 22472330504cSHelge Deller #ifdef CONFIG_USER_ONLY 22482330504cSHelge Deller /* We don't implement space registers in user mode. */ 22496fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 22502330504cSHelge Deller #else 2251967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2252967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 22532330504cSHelge Deller #endif 2254e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 225598a9cb79SRichard Henderson 225698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 225731234768SRichard Henderson return true; 225898a9cb79SRichard Henderson } 225998a9cb79SRichard Henderson 2260e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2261e36f27efSRichard Henderson { 22627b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY 2263e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22647b2d70a1SHelge Deller #else 22656fd0c7bcSRichard Henderson TCGv_i64 tmp; 2266e1b5a5edSRichard Henderson 22677b2d70a1SHelge Deller /* HP-UX 11i and HP ODE use rsm for read-access to PSW */ 22687b2d70a1SHelge Deller if (a->i) { 22697b2d70a1SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22707b2d70a1SHelge Deller } 22717b2d70a1SHelge Deller 2272e1b5a5edSRichard Henderson nullify_over(ctx); 2273e1b5a5edSRichard Henderson 2274aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22756fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 22766fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2277ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2278e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2279e1b5a5edSRichard Henderson 2280e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 228131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 228231234768SRichard Henderson return nullify_end(ctx); 2283e36f27efSRichard Henderson #endif 2284e1b5a5edSRichard Henderson } 2285e1b5a5edSRichard Henderson 2286e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2287e1b5a5edSRichard Henderson { 2288e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2289e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 22906fd0c7bcSRichard Henderson TCGv_i64 tmp; 2291e1b5a5edSRichard Henderson 2292e1b5a5edSRichard Henderson nullify_over(ctx); 2293e1b5a5edSRichard Henderson 2294aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22956fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 22966fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2297ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2298e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2299e1b5a5edSRichard Henderson 2300e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 230131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 230231234768SRichard Henderson return nullify_end(ctx); 2303e36f27efSRichard Henderson #endif 2304e1b5a5edSRichard Henderson } 2305e1b5a5edSRichard Henderson 2306c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2307e1b5a5edSRichard Henderson { 2308e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2309c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 23106fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2311e1b5a5edSRichard Henderson nullify_over(ctx); 2312e1b5a5edSRichard Henderson 2313c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2314aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2315ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2316e1b5a5edSRichard Henderson 2317e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 231831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 231931234768SRichard Henderson return nullify_end(ctx); 2320c603e14aSRichard Henderson #endif 2321e1b5a5edSRichard Henderson } 2322f49b3537SRichard Henderson 2323e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2324f49b3537SRichard Henderson { 2325f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2326e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2327f49b3537SRichard Henderson nullify_over(ctx); 2328f49b3537SRichard Henderson 2329e36f27efSRichard Henderson if (rfi_r) { 2330ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2331f49b3537SRichard Henderson } else { 2332ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2333f49b3537SRichard Henderson } 233431234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 233507ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 233631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2337f49b3537SRichard Henderson 233831234768SRichard Henderson return nullify_end(ctx); 2339e36f27efSRichard Henderson #endif 2340f49b3537SRichard Henderson } 23416210db05SHelge Deller 2342e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2343e36f27efSRichard Henderson { 2344e36f27efSRichard Henderson return do_rfi(ctx, false); 2345e36f27efSRichard Henderson } 2346e36f27efSRichard Henderson 2347e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2348e36f27efSRichard Henderson { 2349e36f27efSRichard Henderson return do_rfi(ctx, true); 2350e36f27efSRichard Henderson } 2351e36f27efSRichard Henderson 235296927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 23536210db05SHelge Deller { 23546210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 235596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 23566210db05SHelge Deller nullify_over(ctx); 2357ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 235831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 235931234768SRichard Henderson return nullify_end(ctx); 236096927adbSRichard Henderson #endif 23616210db05SHelge Deller } 236296927adbSRichard Henderson 236396927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 236496927adbSRichard Henderson { 236596927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 236696927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 236796927adbSRichard Henderson nullify_over(ctx); 2368ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 236996927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 237096927adbSRichard Henderson return nullify_end(ctx); 237196927adbSRichard Henderson #endif 237296927adbSRichard Henderson } 2373e1b5a5edSRichard Henderson 2374558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx) 23754a4554c6SHelge Deller { 23764a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 23774a4554c6SHelge Deller nullify_over(ctx); 2378558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0])); 2379558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1])); 2380558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2])); 2381558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3])); 2382558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4])); 2383558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5])); 2384558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6])); 23854a4554c6SHelge Deller return nullify_end(ctx); 2386558c09beSRichard Henderson } 2387558c09beSRichard Henderson 23883bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx) 23893bdf2081SHelge Deller { 23903bdf2081SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 23913bdf2081SHelge Deller nullify_over(ctx); 23923bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0])); 23933bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1])); 23943bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2])); 23953bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3])); 23963bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4])); 23973bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5])); 23983bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6])); 23993bdf2081SHelge Deller return nullify_end(ctx); 24003bdf2081SHelge Deller } 24013bdf2081SHelge Deller 2402558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 2403558c09beSRichard Henderson { 2404558c09beSRichard Henderson return do_getshadowregs(ctx); 24054a4554c6SHelge Deller } 24064a4554c6SHelge Deller 2407deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 240898a9cb79SRichard Henderson { 2409deee69a1SRichard Henderson if (a->m) { 24106fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 24116fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 24126fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 241398a9cb79SRichard Henderson 241498a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 24156fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2416deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2417deee69a1SRichard Henderson } 241898a9cb79SRichard Henderson cond_free(&ctx->null_cond); 241931234768SRichard Henderson return true; 242098a9cb79SRichard Henderson } 242198a9cb79SRichard Henderson 2422ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a) 2423ad1fdacdSSven Schnelle { 2424ad1fdacdSSven Schnelle /* End TB for flush instruction cache, so we pick up new insns. */ 2425ad1fdacdSSven Schnelle ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2426ad1fdacdSSven Schnelle return trans_nop_addrx(ctx, a); 2427ad1fdacdSSven Schnelle } 2428ad1fdacdSSven Schnelle 2429deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 243098a9cb79SRichard Henderson { 24316fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2432eed14219SRichard Henderson TCGv_i32 level, want; 24336fd0c7bcSRichard Henderson TCGv_i64 addr; 243498a9cb79SRichard Henderson 243598a9cb79SRichard Henderson nullify_over(ctx); 243698a9cb79SRichard Henderson 2437deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2438deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2439eed14219SRichard Henderson 2440deee69a1SRichard Henderson if (a->imm) { 2441e5d487c9SRichard Henderson level = tcg_constant_i32(a->ri & 3); 244298a9cb79SRichard Henderson } else { 2443eed14219SRichard Henderson level = tcg_temp_new_i32(); 24446fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2445eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 244698a9cb79SRichard Henderson } 244729dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2448eed14219SRichard Henderson 2449ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2450eed14219SRichard Henderson 2451deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 245231234768SRichard Henderson return nullify_end(ctx); 245398a9cb79SRichard Henderson } 245498a9cb79SRichard Henderson 2455deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 24568d6ae7fbSRichard Henderson { 24578577f354SRichard Henderson if (ctx->is_pa20) { 24588577f354SRichard Henderson return false; 24598577f354SRichard Henderson } 2460deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2461deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24626fd0c7bcSRichard Henderson TCGv_i64 addr; 24636fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 24648d6ae7fbSRichard Henderson 24658d6ae7fbSRichard Henderson nullify_over(ctx); 24668d6ae7fbSRichard Henderson 2467deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2468deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2469deee69a1SRichard Henderson if (a->addr) { 24708577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 24718d6ae7fbSRichard Henderson } else { 24728577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 24738d6ae7fbSRichard Henderson } 24748d6ae7fbSRichard Henderson 247532dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 247632dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 247731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 247831234768SRichard Henderson } 247931234768SRichard Henderson return nullify_end(ctx); 2480deee69a1SRichard Henderson #endif 24818d6ae7fbSRichard Henderson } 248263300a00SRichard Henderson 2483eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 248463300a00SRichard Henderson { 2485deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2486deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24876fd0c7bcSRichard Henderson TCGv_i64 addr; 24886fd0c7bcSRichard Henderson TCGv_i64 ofs; 248963300a00SRichard Henderson 249063300a00SRichard Henderson nullify_over(ctx); 249163300a00SRichard Henderson 2492deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2493eb25d10fSHelge Deller 2494eb25d10fSHelge Deller /* 2495eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2496eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2497eb25d10fSHelge Deller */ 2498eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2499eb25d10fSHelge Deller if (ctx->is_pa20) { 2500eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 250163300a00SRichard Henderson } 2502eb25d10fSHelge Deller 2503eb25d10fSHelge Deller if (local) { 2504eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 250563300a00SRichard Henderson } else { 2506ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 250763300a00SRichard Henderson } 250863300a00SRichard Henderson 2509eb25d10fSHelge Deller if (a->m) { 2510eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2511eb25d10fSHelge Deller } 2512eb25d10fSHelge Deller 2513eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2514eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2515eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2516eb25d10fSHelge Deller } 2517eb25d10fSHelge Deller return nullify_end(ctx); 2518eb25d10fSHelge Deller #endif 2519eb25d10fSHelge Deller } 2520eb25d10fSHelge Deller 2521eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2522eb25d10fSHelge Deller { 2523eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2524eb25d10fSHelge Deller } 2525eb25d10fSHelge Deller 2526eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2527eb25d10fSHelge Deller { 2528eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2529eb25d10fSHelge Deller } 2530eb25d10fSHelge Deller 2531eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2532eb25d10fSHelge Deller { 2533eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2534eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2535eb25d10fSHelge Deller nullify_over(ctx); 2536eb25d10fSHelge Deller 2537eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2538eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2539eb25d10fSHelge Deller 254063300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 254132dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 254231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 254331234768SRichard Henderson } 254431234768SRichard Henderson return nullify_end(ctx); 2545deee69a1SRichard Henderson #endif 254663300a00SRichard Henderson } 25472dfcca9fSRichard Henderson 25486797c315SNick Hudson /* 25496797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 25506797c315SNick Hudson * See 25516797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 25526797c315SNick Hudson * page 13-9 (195/206) 25536797c315SNick Hudson */ 25546797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 25556797c315SNick Hudson { 25568577f354SRichard Henderson if (ctx->is_pa20) { 25578577f354SRichard Henderson return false; 25588577f354SRichard Henderson } 25596797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 25606797c315SNick Hudson #ifndef CONFIG_USER_ONLY 25616fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 25626fd0c7bcSRichard Henderson TCGv_i64 reg; 25636797c315SNick Hudson 25646797c315SNick Hudson nullify_over(ctx); 25656797c315SNick Hudson 25666797c315SNick Hudson /* 25676797c315SNick Hudson * FIXME: 25686797c315SNick Hudson * if (not (pcxl or pcxl2)) 25696797c315SNick Hudson * return gen_illegal(ctx); 25706797c315SNick Hudson */ 25716797c315SNick Hudson 25726fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 25736fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 25746fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 25756797c315SNick Hudson 2576ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 25776797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 25786797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2579ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 25806797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 25816797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 25826797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2583d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 25846797c315SNick Hudson 25856797c315SNick Hudson reg = load_gpr(ctx, a->r); 25866797c315SNick Hudson if (a->addr) { 25878577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 25886797c315SNick Hudson } else { 25898577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 25906797c315SNick Hudson } 25916797c315SNick Hudson 25926797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 25936797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 25946797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 25956797c315SNick Hudson } 25966797c315SNick Hudson return nullify_end(ctx); 25976797c315SNick Hudson #endif 25986797c315SNick Hudson } 25996797c315SNick Hudson 26008577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 26018577f354SRichard Henderson { 26028577f354SRichard Henderson if (!ctx->is_pa20) { 26038577f354SRichard Henderson return false; 26048577f354SRichard Henderson } 26058577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 26068577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 26078577f354SRichard Henderson nullify_over(ctx); 26088577f354SRichard Henderson { 26098577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 26108577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 26118577f354SRichard Henderson 26128577f354SRichard Henderson if (a->data) { 26138577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 26148577f354SRichard Henderson } else { 26158577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 26168577f354SRichard Henderson } 26178577f354SRichard Henderson } 26188577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 26198577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 26208577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 26218577f354SRichard Henderson } 26228577f354SRichard Henderson return nullify_end(ctx); 26238577f354SRichard Henderson #endif 26248577f354SRichard Henderson } 26258577f354SRichard Henderson 2626deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 26272dfcca9fSRichard Henderson { 2628deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2629deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 26306fd0c7bcSRichard Henderson TCGv_i64 vaddr; 26316fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 26322dfcca9fSRichard Henderson 26332dfcca9fSRichard Henderson nullify_over(ctx); 26342dfcca9fSRichard Henderson 2635deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 26362dfcca9fSRichard Henderson 2637aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2638ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 26392dfcca9fSRichard Henderson 26402dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2641deee69a1SRichard Henderson if (a->m) { 2642deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 26432dfcca9fSRichard Henderson } 2644deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 26452dfcca9fSRichard Henderson 264631234768SRichard Henderson return nullify_end(ctx); 2647deee69a1SRichard Henderson #endif 26482dfcca9fSRichard Henderson } 264943a97b81SRichard Henderson 2650deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 265143a97b81SRichard Henderson { 265243a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 265343a97b81SRichard Henderson 265443a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 265543a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 265643a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 265743a97b81SRichard Henderson since the entire address space is coherent. */ 2658a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 265943a97b81SRichard Henderson 266031234768SRichard Henderson cond_free(&ctx->null_cond); 266131234768SRichard Henderson return true; 266243a97b81SRichard Henderson } 266398a9cb79SRichard Henderson 2664faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2665b2167459SRichard Henderson { 26660c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2667b2167459SRichard Henderson } 2668b2167459SRichard Henderson 2669faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2670b2167459SRichard Henderson { 26710c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2672b2167459SRichard Henderson } 2673b2167459SRichard Henderson 2674faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2675b2167459SRichard Henderson { 26760c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2677b2167459SRichard Henderson } 2678b2167459SRichard Henderson 2679faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2680b2167459SRichard Henderson { 26810c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 26820c982a28SRichard Henderson } 2683b2167459SRichard Henderson 2684faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 26850c982a28SRichard Henderson { 26860c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 26870c982a28SRichard Henderson } 26880c982a28SRichard Henderson 268963c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 26900c982a28SRichard Henderson { 26910c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 26920c982a28SRichard Henderson } 26930c982a28SRichard Henderson 269463c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 26950c982a28SRichard Henderson { 26960c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 26970c982a28SRichard Henderson } 26980c982a28SRichard Henderson 269963c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 27000c982a28SRichard Henderson { 27010c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 27020c982a28SRichard Henderson } 27030c982a28SRichard Henderson 270463c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 27050c982a28SRichard Henderson { 27060c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 27070c982a28SRichard Henderson } 27080c982a28SRichard Henderson 270963c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 27100c982a28SRichard Henderson { 27110c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 27120c982a28SRichard Henderson } 27130c982a28SRichard Henderson 271463c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 27150c982a28SRichard Henderson { 27160c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 27170c982a28SRichard Henderson } 27180c982a28SRichard Henderson 2719fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 27200c982a28SRichard Henderson { 27216fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 27220c982a28SRichard Henderson } 27230c982a28SRichard Henderson 2724fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 27250c982a28SRichard Henderson { 27266fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 27270c982a28SRichard Henderson } 27280c982a28SRichard Henderson 2729fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 27300c982a28SRichard Henderson { 27310c982a28SRichard Henderson if (a->cf == 0) { 27320c982a28SRichard Henderson unsigned r2 = a->r2; 27330c982a28SRichard Henderson unsigned r1 = a->r1; 27340c982a28SRichard Henderson unsigned rt = a->t; 27350c982a28SRichard Henderson 27367aee8189SRichard Henderson if (rt == 0) { /* NOP */ 27377aee8189SRichard Henderson cond_free(&ctx->null_cond); 27387aee8189SRichard Henderson return true; 27397aee8189SRichard Henderson } 27407aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2741b2167459SRichard Henderson if (r1 == 0) { 27426fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 27436fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2744b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2745b2167459SRichard Henderson } else { 2746b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2747b2167459SRichard Henderson } 2748b2167459SRichard Henderson cond_free(&ctx->null_cond); 274931234768SRichard Henderson return true; 2750b2167459SRichard Henderson } 27517aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 27527aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 27537aee8189SRichard Henderson * 27547aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 27557aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 27567aee8189SRichard Henderson * currently implemented as idle. 27577aee8189SRichard Henderson */ 27587aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 27597aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 27607aee8189SRichard Henderson until the next timer interrupt. */ 27617aee8189SRichard Henderson nullify_over(ctx); 27627aee8189SRichard Henderson 27637aee8189SRichard Henderson /* Advance the instruction queue. */ 2764bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_b, NULL); 27657aee8189SRichard Henderson nullify_set(ctx, 0); 27667aee8189SRichard Henderson 27677aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2768ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 276929dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 27707aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 27717aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 27727aee8189SRichard Henderson 27737aee8189SRichard Henderson return nullify_end(ctx); 27747aee8189SRichard Henderson } 27757aee8189SRichard Henderson #endif 27767aee8189SRichard Henderson } 27776fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 27787aee8189SRichard Henderson } 2779b2167459SRichard Henderson 2780fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2781b2167459SRichard Henderson { 27826fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 27830c982a28SRichard Henderson } 27840c982a28SRichard Henderson 2785345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 27860c982a28SRichard Henderson { 27876fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2788b2167459SRichard Henderson 27890c982a28SRichard Henderson if (a->cf) { 2790b2167459SRichard Henderson nullify_over(ctx); 2791b2167459SRichard Henderson } 27920c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 27930c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2794345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 279531234768SRichard Henderson return nullify_end(ctx); 2796b2167459SRichard Henderson } 2797b2167459SRichard Henderson 2798af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2799b2167459SRichard Henderson { 280046bb3d46SRichard Henderson TCGv_i64 tcg_r1, tcg_r2, dest; 2801b2167459SRichard Henderson 28020c982a28SRichard Henderson if (a->cf) { 2803b2167459SRichard Henderson nullify_over(ctx); 2804b2167459SRichard Henderson } 280546bb3d46SRichard Henderson 28060c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 28070c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 280846bb3d46SRichard Henderson dest = dest_gpr(ctx, a->t); 280946bb3d46SRichard Henderson 281046bb3d46SRichard Henderson tcg_gen_xor_i64(dest, tcg_r1, tcg_r2); 281146bb3d46SRichard Henderson save_gpr(ctx, a->t, dest); 281246bb3d46SRichard Henderson 281346bb3d46SRichard Henderson cond_free(&ctx->null_cond); 281446bb3d46SRichard Henderson if (a->cf) { 281546bb3d46SRichard Henderson ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest); 281646bb3d46SRichard Henderson } 281746bb3d46SRichard Henderson 281831234768SRichard Henderson return nullify_end(ctx); 2819b2167459SRichard Henderson } 2820b2167459SRichard Henderson 2821af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2822b2167459SRichard Henderson { 28236fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2824b2167459SRichard Henderson 2825ababac16SRichard Henderson if (a->cf == 0) { 2826ababac16SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2827ababac16SRichard Henderson tmp = dest_gpr(ctx, a->t); 2828ababac16SRichard Henderson 2829ababac16SRichard Henderson if (a->r1 == 0) { 2830ababac16SRichard Henderson /* UADDCM r0,src,dst is the common idiom for dst = ~src. */ 2831ababac16SRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 2832ababac16SRichard Henderson } else { 2833ababac16SRichard Henderson /* 2834ababac16SRichard Henderson * Recall that r1 - r2 == r1 + ~r2 + 1. 2835ababac16SRichard Henderson * Thus r1 + ~r2 == r1 - r2 - 1, 2836ababac16SRichard Henderson * which does not require an extra temporary. 2837ababac16SRichard Henderson */ 2838ababac16SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 2839ababac16SRichard Henderson tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2); 2840ababac16SRichard Henderson tcg_gen_subi_i64(tmp, tmp, 1); 2841b2167459SRichard Henderson } 2842ababac16SRichard Henderson save_gpr(ctx, a->t, tmp); 2843ababac16SRichard Henderson cond_free(&ctx->null_cond); 2844ababac16SRichard Henderson return true; 2845ababac16SRichard Henderson } 2846ababac16SRichard Henderson 2847ababac16SRichard Henderson nullify_over(ctx); 28480c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 28490c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2850aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 28516fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 285246bb3d46SRichard Henderson do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true); 285331234768SRichard Henderson return nullify_end(ctx); 2854b2167459SRichard Henderson } 2855b2167459SRichard Henderson 2856af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2857b2167459SRichard Henderson { 28580c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 28590c982a28SRichard Henderson } 28600c982a28SRichard Henderson 2861af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 28620c982a28SRichard Henderson { 28630c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 28640c982a28SRichard Henderson } 28650c982a28SRichard Henderson 2866af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 28670c982a28SRichard Henderson { 28686fd0c7bcSRichard Henderson TCGv_i64 tmp; 2869b2167459SRichard Henderson 2870b2167459SRichard Henderson nullify_over(ctx); 2871b2167459SRichard Henderson 2872aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2873d0ae87a2SRichard Henderson tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4); 2874b2167459SRichard Henderson if (!is_i) { 28756fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2876b2167459SRichard Henderson } 28776fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 28786fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 287946bb3d46SRichard Henderson do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp, 288046bb3d46SRichard Henderson a->cf, a->d, false, is_i); 288131234768SRichard Henderson return nullify_end(ctx); 2882b2167459SRichard Henderson } 2883b2167459SRichard Henderson 2884af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2885b2167459SRichard Henderson { 28860c982a28SRichard Henderson return do_dcor(ctx, a, false); 28870c982a28SRichard Henderson } 28880c982a28SRichard Henderson 2889af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 28900c982a28SRichard Henderson { 28910c982a28SRichard Henderson return do_dcor(ctx, a, true); 28920c982a28SRichard Henderson } 28930c982a28SRichard Henderson 28940c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 28950c982a28SRichard Henderson { 2896a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 2897b2167459SRichard Henderson 2898b2167459SRichard Henderson nullify_over(ctx); 2899b2167459SRichard Henderson 29000c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 29010c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2902b2167459SRichard Henderson 2903aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2904aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2905aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2906aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2907b2167459SRichard Henderson 2908b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 29096fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 29106fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2911b2167459SRichard Henderson 291272ca8753SRichard Henderson /* 291372ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 291472ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 291572ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 291672ca8753SRichard Henderson * proper inputs to the addition without movcond. 291772ca8753SRichard Henderson */ 29186fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 29196fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 29206fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 292172ca8753SRichard Henderson 2922a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2923a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2924a4db4a78SRichard Henderson addc, ctx->zero); 2925b2167459SRichard Henderson 2926b2167459SRichard Henderson /* Write back the result register. */ 29270c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2928b2167459SRichard Henderson 2929b2167459SRichard Henderson /* Write back PSW[CB]. */ 29306fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 29316fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2932b2167459SRichard Henderson 2933f8f5986eSRichard Henderson /* 2934f8f5986eSRichard Henderson * Write back PSW[V] for the division step. 2935f8f5986eSRichard Henderson * Shift cb{8} from where it lives in bit 32 to bit 31, 2936f8f5986eSRichard Henderson * so that it overlaps r2{32} in bit 31. 2937f8f5986eSRichard Henderson */ 2938f8f5986eSRichard Henderson tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1); 29396fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2940b2167459SRichard Henderson 2941b2167459SRichard Henderson /* Install the new nullification. */ 29420c982a28SRichard Henderson if (a->cf) { 2943f8f5986eSRichard Henderson TCGv_i64 sv = NULL, uv = NULL; 2944b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2945f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false); 2946f8f5986eSRichard Henderson } else if (cond_need_cb(a->cf >> 1)) { 2947f8f5986eSRichard Henderson uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false); 2948b2167459SRichard Henderson } 2949f8f5986eSRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv); 2950b2167459SRichard Henderson } 2951b2167459SRichard Henderson 295231234768SRichard Henderson return nullify_end(ctx); 2953b2167459SRichard Henderson } 2954b2167459SRichard Henderson 29550588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2956b2167459SRichard Henderson { 29570588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 29580588e061SRichard Henderson } 29590588e061SRichard Henderson 29600588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 29610588e061SRichard Henderson { 29620588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 29630588e061SRichard Henderson } 29640588e061SRichard Henderson 29650588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 29660588e061SRichard Henderson { 29670588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 29680588e061SRichard Henderson } 29690588e061SRichard Henderson 29700588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 29710588e061SRichard Henderson { 29720588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 29730588e061SRichard Henderson } 29740588e061SRichard Henderson 29750588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 29760588e061SRichard Henderson { 29770588e061SRichard Henderson return do_sub_imm(ctx, a, false); 29780588e061SRichard Henderson } 29790588e061SRichard Henderson 29800588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 29810588e061SRichard Henderson { 29820588e061SRichard Henderson return do_sub_imm(ctx, a, true); 29830588e061SRichard Henderson } 29840588e061SRichard Henderson 2985345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 29860588e061SRichard Henderson { 29876fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 2988b2167459SRichard Henderson 29890588e061SRichard Henderson if (a->cf) { 2990b2167459SRichard Henderson nullify_over(ctx); 2991b2167459SRichard Henderson } 2992b2167459SRichard Henderson 29936fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 29940588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 2995345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2996b2167459SRichard Henderson 299731234768SRichard Henderson return nullify_end(ctx); 2998b2167459SRichard Henderson } 2999b2167459SRichard Henderson 30000843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 30010843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 30020843563fSRichard Henderson { 30030843563fSRichard Henderson TCGv_i64 r1, r2, dest; 30040843563fSRichard Henderson 30050843563fSRichard Henderson if (!ctx->is_pa20) { 30060843563fSRichard Henderson return false; 30070843563fSRichard Henderson } 30080843563fSRichard Henderson 30090843563fSRichard Henderson nullify_over(ctx); 30100843563fSRichard Henderson 30110843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 30120843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 30130843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 30140843563fSRichard Henderson 30150843563fSRichard Henderson fn(dest, r1, r2); 30160843563fSRichard Henderson save_gpr(ctx, a->t, dest); 30170843563fSRichard Henderson 30180843563fSRichard Henderson return nullify_end(ctx); 30190843563fSRichard Henderson } 30200843563fSRichard Henderson 3021151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 3022151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 3023151f309bSRichard Henderson { 3024151f309bSRichard Henderson TCGv_i64 r, dest; 3025151f309bSRichard Henderson 3026151f309bSRichard Henderson if (!ctx->is_pa20) { 3027151f309bSRichard Henderson return false; 3028151f309bSRichard Henderson } 3029151f309bSRichard Henderson 3030151f309bSRichard Henderson nullify_over(ctx); 3031151f309bSRichard Henderson 3032151f309bSRichard Henderson r = load_gpr(ctx, a->r); 3033151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 3034151f309bSRichard Henderson 3035151f309bSRichard Henderson fn(dest, r, a->i); 3036151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 3037151f309bSRichard Henderson 3038151f309bSRichard Henderson return nullify_end(ctx); 3039151f309bSRichard Henderson } 3040151f309bSRichard Henderson 30413bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 30423bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 30433bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 30443bbb8e48SRichard Henderson { 30453bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 30463bbb8e48SRichard Henderson 30473bbb8e48SRichard Henderson if (!ctx->is_pa20) { 30483bbb8e48SRichard Henderson return false; 30493bbb8e48SRichard Henderson } 30503bbb8e48SRichard Henderson 30513bbb8e48SRichard Henderson nullify_over(ctx); 30523bbb8e48SRichard Henderson 30533bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 30543bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 30553bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 30563bbb8e48SRichard Henderson 30573bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 30583bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 30593bbb8e48SRichard Henderson 30603bbb8e48SRichard Henderson return nullify_end(ctx); 30613bbb8e48SRichard Henderson } 30623bbb8e48SRichard Henderson 30630843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 30640843563fSRichard Henderson { 30650843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 30660843563fSRichard Henderson } 30670843563fSRichard Henderson 30680843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 30690843563fSRichard Henderson { 30700843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 30710843563fSRichard Henderson } 30720843563fSRichard Henderson 30730843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 30740843563fSRichard Henderson { 30750843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 30760843563fSRichard Henderson } 30770843563fSRichard Henderson 30781b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 30791b3cb7c8SRichard Henderson { 30801b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 30811b3cb7c8SRichard Henderson } 30821b3cb7c8SRichard Henderson 3083151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 3084151f309bSRichard Henderson { 3085151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 3086151f309bSRichard Henderson } 3087151f309bSRichard Henderson 3088151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 3089151f309bSRichard Henderson { 3090151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 3091151f309bSRichard Henderson } 3092151f309bSRichard Henderson 3093151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 3094151f309bSRichard Henderson { 3095151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 3096151f309bSRichard Henderson } 3097151f309bSRichard Henderson 30983bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 30993bbb8e48SRichard Henderson { 31003bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 31013bbb8e48SRichard Henderson } 31023bbb8e48SRichard Henderson 31033bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 31043bbb8e48SRichard Henderson { 31053bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 31063bbb8e48SRichard Henderson } 31073bbb8e48SRichard Henderson 310810c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 310910c9e58dSRichard Henderson { 311010c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 311110c9e58dSRichard Henderson } 311210c9e58dSRichard Henderson 311310c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 311410c9e58dSRichard Henderson { 311510c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 311610c9e58dSRichard Henderson } 311710c9e58dSRichard Henderson 311810c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 311910c9e58dSRichard Henderson { 312010c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 312110c9e58dSRichard Henderson } 312210c9e58dSRichard Henderson 3123c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3124c2a7ee3fSRichard Henderson { 3125c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 3126c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3127c2a7ee3fSRichard Henderson 3128c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 3129c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 3130c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 3131c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3132c2a7ee3fSRichard Henderson } 3133c2a7ee3fSRichard Henderson 3134c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 3135c2a7ee3fSRichard Henderson { 3136c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 3137c2a7ee3fSRichard Henderson } 3138c2a7ee3fSRichard Henderson 3139c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3140c2a7ee3fSRichard Henderson { 3141c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 3142c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3143c2a7ee3fSRichard Henderson 3144c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 3145c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 3146c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 3147c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3148c2a7ee3fSRichard Henderson } 3149c2a7ee3fSRichard Henderson 3150c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 3151c2a7ee3fSRichard Henderson { 3152c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 3153c2a7ee3fSRichard Henderson } 3154c2a7ee3fSRichard Henderson 3155c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3156c2a7ee3fSRichard Henderson { 3157c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3158c2a7ee3fSRichard Henderson 3159c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 3160c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 3161c2a7ee3fSRichard Henderson } 3162c2a7ee3fSRichard Henderson 3163c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 3164c2a7ee3fSRichard Henderson { 3165c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 3166c2a7ee3fSRichard Henderson } 3167c2a7ee3fSRichard Henderson 3168c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3169c2a7ee3fSRichard Henderson { 3170c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 3171c2a7ee3fSRichard Henderson } 3172c2a7ee3fSRichard Henderson 3173c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 3174c2a7ee3fSRichard Henderson { 3175c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 3176c2a7ee3fSRichard Henderson } 3177c2a7ee3fSRichard Henderson 31784e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 31794e7abdb1SRichard Henderson { 31804e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 31814e7abdb1SRichard Henderson 31824e7abdb1SRichard Henderson if (!ctx->is_pa20) { 31834e7abdb1SRichard Henderson return false; 31844e7abdb1SRichard Henderson } 31854e7abdb1SRichard Henderson 31864e7abdb1SRichard Henderson nullify_over(ctx); 31874e7abdb1SRichard Henderson 31884e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 31894e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 31904e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 31914e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 31924e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 31934e7abdb1SRichard Henderson 31944e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 31954e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 31964e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 31974e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 31984e7abdb1SRichard Henderson 31994e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 32004e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 32014e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 32024e7abdb1SRichard Henderson 32034e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 32044e7abdb1SRichard Henderson return nullify_end(ctx); 32054e7abdb1SRichard Henderson } 32064e7abdb1SRichard Henderson 32071cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 320896d6407fSRichard Henderson { 3209b5caa17cSRichard Henderson if (ctx->is_pa20) { 3210b5caa17cSRichard Henderson /* 3211b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3212b5caa17cSRichard Henderson * Any base modification still occurs. 3213b5caa17cSRichard Henderson */ 3214b5caa17cSRichard Henderson if (a->t == 0) { 3215b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3216b5caa17cSRichard Henderson } 3217b5caa17cSRichard Henderson } else if (a->size > MO_32) { 32180786a3b6SHelge Deller return gen_illegal(ctx); 3219c53e401eSRichard Henderson } 32201cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 32211cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 322296d6407fSRichard Henderson } 322396d6407fSRichard Henderson 32241cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 322596d6407fSRichard Henderson { 32261cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3227c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 32280786a3b6SHelge Deller return gen_illegal(ctx); 322996d6407fSRichard Henderson } 3230c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 32310786a3b6SHelge Deller } 323296d6407fSRichard Henderson 32331cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 323496d6407fSRichard Henderson { 3235b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3236a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 32376fd0c7bcSRichard Henderson TCGv_i64 addr; 323896d6407fSRichard Henderson 3239c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 324051416c4eSRichard Henderson return gen_illegal(ctx); 324151416c4eSRichard Henderson } 324251416c4eSRichard Henderson 324396d6407fSRichard Henderson nullify_over(ctx); 324496d6407fSRichard Henderson 32451cd012a5SRichard Henderson if (a->m) { 324686f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 324786f8d05fSRichard Henderson we see the result of the load. */ 3248aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 324996d6407fSRichard Henderson } else { 32501cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 325196d6407fSRichard Henderson } 325296d6407fSRichard Henderson 3253c3ea1996SSven Schnelle form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0, 325417fe594cSRichard Henderson a->disp, a->sp, a->m, MMU_DISABLED(ctx)); 3255b1af755cSRichard Henderson 3256b1af755cSRichard Henderson /* 3257b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3258b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3259b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3260b1af755cSRichard Henderson * 3261b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3262b1af755cSRichard Henderson * with the ,co completer. 3263b1af755cSRichard Henderson */ 3264b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3265b1af755cSRichard Henderson 3266a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3267b1af755cSRichard Henderson 32681cd012a5SRichard Henderson if (a->m) { 32691cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 327096d6407fSRichard Henderson } 32711cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 327296d6407fSRichard Henderson 327331234768SRichard Henderson return nullify_end(ctx); 327496d6407fSRichard Henderson } 327596d6407fSRichard Henderson 32761cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 327796d6407fSRichard Henderson { 32786fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 32796fd0c7bcSRichard Henderson TCGv_i64 addr; 328096d6407fSRichard Henderson 328196d6407fSRichard Henderson nullify_over(ctx); 328296d6407fSRichard Henderson 32831cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 328417fe594cSRichard Henderson MMU_DISABLED(ctx)); 32851cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 32861cd012a5SRichard Henderson if (a->a) { 3287f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3288ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3289f9f46db4SEmilio G. Cota } else { 3290ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3291f9f46db4SEmilio G. Cota } 3292f9f46db4SEmilio G. Cota } else { 3293f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3294ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 329596d6407fSRichard Henderson } else { 3296ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 329796d6407fSRichard Henderson } 3298f9f46db4SEmilio G. Cota } 32991cd012a5SRichard Henderson if (a->m) { 33006fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 33011cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 330296d6407fSRichard Henderson } 330396d6407fSRichard Henderson 330431234768SRichard Henderson return nullify_end(ctx); 330596d6407fSRichard Henderson } 330696d6407fSRichard Henderson 330725460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 330825460fc5SRichard Henderson { 33096fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 33106fd0c7bcSRichard Henderson TCGv_i64 addr; 331125460fc5SRichard Henderson 331225460fc5SRichard Henderson if (!ctx->is_pa20) { 331325460fc5SRichard Henderson return false; 331425460fc5SRichard Henderson } 331525460fc5SRichard Henderson nullify_over(ctx); 331625460fc5SRichard Henderson 331725460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 331817fe594cSRichard Henderson MMU_DISABLED(ctx)); 331925460fc5SRichard Henderson val = load_gpr(ctx, a->r); 332025460fc5SRichard Henderson if (a->a) { 332125460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 332225460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 332325460fc5SRichard Henderson } else { 332425460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 332525460fc5SRichard Henderson } 332625460fc5SRichard Henderson } else { 332725460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 332825460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 332925460fc5SRichard Henderson } else { 333025460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 333125460fc5SRichard Henderson } 333225460fc5SRichard Henderson } 333325460fc5SRichard Henderson if (a->m) { 33346fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 333525460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 333625460fc5SRichard Henderson } 333725460fc5SRichard Henderson 333825460fc5SRichard Henderson return nullify_end(ctx); 333925460fc5SRichard Henderson } 334025460fc5SRichard Henderson 33411cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3342d0a851ccSRichard Henderson { 3343d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3344d0a851ccSRichard Henderson 3345d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3346451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 33471cd012a5SRichard Henderson trans_ld(ctx, a); 3348d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 334931234768SRichard Henderson return true; 3350d0a851ccSRichard Henderson } 3351d0a851ccSRichard Henderson 33521cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3353d0a851ccSRichard Henderson { 3354d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3355d0a851ccSRichard Henderson 3356d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3357451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 33581cd012a5SRichard Henderson trans_st(ctx, a); 3359d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 336031234768SRichard Henderson return true; 3361d0a851ccSRichard Henderson } 336295412a61SRichard Henderson 33630588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3364b2167459SRichard Henderson { 33656fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3366b2167459SRichard Henderson 33676fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 33680588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3369b2167459SRichard Henderson cond_free(&ctx->null_cond); 337031234768SRichard Henderson return true; 3371b2167459SRichard Henderson } 3372b2167459SRichard Henderson 33730588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3374b2167459SRichard Henderson { 33756fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 33766fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3377b2167459SRichard Henderson 33786fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3379b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3380b2167459SRichard Henderson cond_free(&ctx->null_cond); 338131234768SRichard Henderson return true; 3382b2167459SRichard Henderson } 3383b2167459SRichard Henderson 33840588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3385b2167459SRichard Henderson { 33866fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3387b2167459SRichard Henderson 3388b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3389d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 33900588e061SRichard Henderson if (a->b == 0) { 33916fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3392b2167459SRichard Henderson } else { 33936fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3394b2167459SRichard Henderson } 33950588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3396b2167459SRichard Henderson cond_free(&ctx->null_cond); 339731234768SRichard Henderson return true; 3398b2167459SRichard Henderson } 3399b2167459SRichard Henderson 34006fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3401e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 340298cd9ca7SRichard Henderson { 34036fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 340498cd9ca7SRichard Henderson DisasCond cond; 340598cd9ca7SRichard Henderson 340698cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3407aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 340898cd9ca7SRichard Henderson 34096fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 341098cd9ca7SRichard Henderson 3411f764718dSRichard Henderson sv = NULL; 3412b47a4a02SSven Schnelle if (cond_need_sv(c)) { 341398cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 341498cd9ca7SRichard Henderson } 341598cd9ca7SRichard Henderson 34164fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 341701afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 341898cd9ca7SRichard Henderson } 341998cd9ca7SRichard Henderson 342001afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 342198cd9ca7SRichard Henderson { 3422e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3423e9efd4bcSRichard Henderson return false; 3424e9efd4bcSRichard Henderson } 342501afb7beSRichard Henderson nullify_over(ctx); 3426e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3427e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 342801afb7beSRichard Henderson } 342901afb7beSRichard Henderson 343001afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 343101afb7beSRichard Henderson { 3432c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3433c65c3ee1SRichard Henderson return false; 3434c65c3ee1SRichard Henderson } 343501afb7beSRichard Henderson nullify_over(ctx); 34366fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3437c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 343801afb7beSRichard Henderson } 343901afb7beSRichard Henderson 34406fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 344101afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 344201afb7beSRichard Henderson { 34436fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 344498cd9ca7SRichard Henderson DisasCond cond; 3445bdcccc17SRichard Henderson bool d = false; 344698cd9ca7SRichard Henderson 3447f25d3160SRichard Henderson /* 3448f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3449f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3450f25d3160SRichard Henderson */ 3451f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3452f25d3160SRichard Henderson d = c >= 5; 3453f25d3160SRichard Henderson if (d) { 3454f25d3160SRichard Henderson c &= 3; 3455f25d3160SRichard Henderson } 3456f25d3160SRichard Henderson } 3457f25d3160SRichard Henderson 345898cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3459aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3460f764718dSRichard Henderson sv = NULL; 3461bdcccc17SRichard Henderson cb_cond = NULL; 346298cd9ca7SRichard Henderson 3463b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3464aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3465aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3466bdcccc17SRichard Henderson 34676fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 34686fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 34696fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 34706fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3471bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3472b47a4a02SSven Schnelle } else { 34736fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3474b47a4a02SSven Schnelle } 3475b47a4a02SSven Schnelle if (cond_need_sv(c)) { 3476f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d); 347798cd9ca7SRichard Henderson } 347898cd9ca7SRichard Henderson 3479a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 348043675d20SSven Schnelle save_gpr(ctx, r, dest); 348101afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 348298cd9ca7SRichard Henderson } 348398cd9ca7SRichard Henderson 348401afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 348598cd9ca7SRichard Henderson { 348601afb7beSRichard Henderson nullify_over(ctx); 348701afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 348801afb7beSRichard Henderson } 348901afb7beSRichard Henderson 349001afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 349101afb7beSRichard Henderson { 349201afb7beSRichard Henderson nullify_over(ctx); 34936fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 349401afb7beSRichard Henderson } 349501afb7beSRichard Henderson 349601afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 349701afb7beSRichard Henderson { 34986fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 349998cd9ca7SRichard Henderson DisasCond cond; 350098cd9ca7SRichard Henderson 350198cd9ca7SRichard Henderson nullify_over(ctx); 350298cd9ca7SRichard Henderson 3503aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 350401afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 350582d0c831SRichard Henderson if (a->d) { 350682d0c831SRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 350782d0c831SRichard Henderson } else { 35081e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 35096fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 35106fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 35111e9ab9fbSRichard Henderson } 351298cd9ca7SRichard Henderson 35134c42fd0dSRichard Henderson cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0); 351401afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 351598cd9ca7SRichard Henderson } 351698cd9ca7SRichard Henderson 351701afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 351898cd9ca7SRichard Henderson { 351901afb7beSRichard Henderson DisasCond cond; 3520*b041ec9dSRichard Henderson int p = a->p | (a->d ? 0 : 32); 352101afb7beSRichard Henderson 352201afb7beSRichard Henderson nullify_over(ctx); 3523*b041ec9dSRichard Henderson cond = cond_make_vi(a->c ? TCG_COND_TSTEQ : TCG_COND_TSTNE, 3524*b041ec9dSRichard Henderson load_gpr(ctx, a->r), 1ull << (63 - p)); 352501afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 352601afb7beSRichard Henderson } 352701afb7beSRichard Henderson 352801afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 352901afb7beSRichard Henderson { 35306fd0c7bcSRichard Henderson TCGv_i64 dest; 353198cd9ca7SRichard Henderson DisasCond cond; 353298cd9ca7SRichard Henderson 353398cd9ca7SRichard Henderson nullify_over(ctx); 353498cd9ca7SRichard Henderson 353501afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 353601afb7beSRichard Henderson if (a->r1 == 0) { 35376fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 353898cd9ca7SRichard Henderson } else { 35396fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 354098cd9ca7SRichard Henderson } 354198cd9ca7SRichard Henderson 35424fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 35434fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 354401afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 354501afb7beSRichard Henderson } 354601afb7beSRichard Henderson 354701afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 354801afb7beSRichard Henderson { 35496fd0c7bcSRichard Henderson TCGv_i64 dest; 355001afb7beSRichard Henderson DisasCond cond; 355101afb7beSRichard Henderson 355201afb7beSRichard Henderson nullify_over(ctx); 355301afb7beSRichard Henderson 355401afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 35556fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 355601afb7beSRichard Henderson 35574fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 35584fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 355901afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 356098cd9ca7SRichard Henderson } 356198cd9ca7SRichard Henderson 3562f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 35630b1347d2SRichard Henderson { 35646fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 35650b1347d2SRichard Henderson 3566f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3567f7b775a9SRichard Henderson return false; 3568f7b775a9SRichard Henderson } 356930878590SRichard Henderson if (a->c) { 35700b1347d2SRichard Henderson nullify_over(ctx); 35710b1347d2SRichard Henderson } 35720b1347d2SRichard Henderson 357330878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3574f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 357530878590SRichard Henderson if (a->r1 == 0) { 3576f7b775a9SRichard Henderson if (a->d) { 35776fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3578f7b775a9SRichard Henderson } else { 3579aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3580f7b775a9SRichard Henderson 35816fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 35826fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 35836fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3584f7b775a9SRichard Henderson } 358530878590SRichard Henderson } else if (a->r1 == a->r2) { 3586f7b775a9SRichard Henderson if (a->d) { 35876fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3588f7b775a9SRichard Henderson } else { 35890b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3590e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3591e1d635e8SRichard Henderson 35926fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 35936fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3594f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3595e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 35966fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3597f7b775a9SRichard Henderson } 3598f7b775a9SRichard Henderson } else { 35996fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3600f7b775a9SRichard Henderson 3601f7b775a9SRichard Henderson if (a->d) { 3602aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3603aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3604f7b775a9SRichard Henderson 36056fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 3606a01491a2SHelge Deller tcg_gen_shl_i64(t, src1, n); 36076fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 3608a01491a2SHelge Deller tcg_gen_shr_i64(dest, src2, cpu_sar); 36096fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 36100b1347d2SRichard Henderson } else { 36110b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 36120b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 36130b1347d2SRichard Henderson 36146fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3615967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3616967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 36170b1347d2SRichard Henderson } 3618f7b775a9SRichard Henderson } 361930878590SRichard Henderson save_gpr(ctx, a->t, dest); 36200b1347d2SRichard Henderson 36210b1347d2SRichard Henderson /* Install the new nullification. */ 36220b1347d2SRichard Henderson cond_free(&ctx->null_cond); 362330878590SRichard Henderson if (a->c) { 3624d37fad0aSSven Schnelle ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36250b1347d2SRichard Henderson } 362631234768SRichard Henderson return nullify_end(ctx); 36270b1347d2SRichard Henderson } 36280b1347d2SRichard Henderson 3629f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 36300b1347d2SRichard Henderson { 3631f7b775a9SRichard Henderson unsigned width, sa; 36326fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 36330b1347d2SRichard Henderson 3634f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3635f7b775a9SRichard Henderson return false; 3636f7b775a9SRichard Henderson } 363730878590SRichard Henderson if (a->c) { 36380b1347d2SRichard Henderson nullify_over(ctx); 36390b1347d2SRichard Henderson } 36400b1347d2SRichard Henderson 3641f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3642f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3643f7b775a9SRichard Henderson 364430878590SRichard Henderson dest = dest_gpr(ctx, a->t); 364530878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 364605bfd4dbSRichard Henderson if (a->r1 == 0) { 36476fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3648c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 36496fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3650f7b775a9SRichard Henderson } else { 3651f7b775a9SRichard Henderson assert(!a->d); 3652f7b775a9SRichard Henderson if (a->r1 == a->r2) { 36530b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 36546fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 36550b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 36566fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 36570b1347d2SRichard Henderson } else { 3658967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3659967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 36600b1347d2SRichard Henderson } 3661f7b775a9SRichard Henderson } 366230878590SRichard Henderson save_gpr(ctx, a->t, dest); 36630b1347d2SRichard Henderson 36640b1347d2SRichard Henderson /* Install the new nullification. */ 36650b1347d2SRichard Henderson cond_free(&ctx->null_cond); 366630878590SRichard Henderson if (a->c) { 3667d37fad0aSSven Schnelle ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36680b1347d2SRichard Henderson } 366931234768SRichard Henderson return nullify_end(ctx); 36700b1347d2SRichard Henderson } 36710b1347d2SRichard Henderson 3672bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 36730b1347d2SRichard Henderson { 3674bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 36756fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 36760b1347d2SRichard Henderson 3677bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3678bd792da3SRichard Henderson return false; 3679bd792da3SRichard Henderson } 368030878590SRichard Henderson if (a->c) { 36810b1347d2SRichard Henderson nullify_over(ctx); 36820b1347d2SRichard Henderson } 36830b1347d2SRichard Henderson 368430878590SRichard Henderson dest = dest_gpr(ctx, a->t); 368530878590SRichard Henderson src = load_gpr(ctx, a->r); 3686aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 36870b1347d2SRichard Henderson 36880b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 36896fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 36906fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3691d781cb77SRichard Henderson 369230878590SRichard Henderson if (a->se) { 3693bd792da3SRichard Henderson if (!a->d) { 36946fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3695bd792da3SRichard Henderson src = dest; 3696bd792da3SRichard Henderson } 36976fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 36986fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 36990b1347d2SRichard Henderson } else { 3700bd792da3SRichard Henderson if (!a->d) { 37016fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3702bd792da3SRichard Henderson src = dest; 3703bd792da3SRichard Henderson } 37046fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 37056fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 37060b1347d2SRichard Henderson } 370730878590SRichard Henderson save_gpr(ctx, a->t, dest); 37080b1347d2SRichard Henderson 37090b1347d2SRichard Henderson /* Install the new nullification. */ 37100b1347d2SRichard Henderson cond_free(&ctx->null_cond); 371130878590SRichard Henderson if (a->c) { 3712bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37130b1347d2SRichard Henderson } 371431234768SRichard Henderson return nullify_end(ctx); 37150b1347d2SRichard Henderson } 37160b1347d2SRichard Henderson 3717bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 37180b1347d2SRichard Henderson { 3719bd792da3SRichard Henderson unsigned len, cpos, width; 37206fd0c7bcSRichard Henderson TCGv_i64 dest, src; 37210b1347d2SRichard Henderson 3722bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3723bd792da3SRichard Henderson return false; 3724bd792da3SRichard Henderson } 372530878590SRichard Henderson if (a->c) { 37260b1347d2SRichard Henderson nullify_over(ctx); 37270b1347d2SRichard Henderson } 37280b1347d2SRichard Henderson 3729bd792da3SRichard Henderson len = a->len; 3730bd792da3SRichard Henderson width = a->d ? 64 : 32; 3731bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3732bd792da3SRichard Henderson if (cpos + len > width) { 3733bd792da3SRichard Henderson len = width - cpos; 3734bd792da3SRichard Henderson } 3735bd792da3SRichard Henderson 373630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 373730878590SRichard Henderson src = load_gpr(ctx, a->r); 373830878590SRichard Henderson if (a->se) { 37396fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 37400b1347d2SRichard Henderson } else { 37416fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 37420b1347d2SRichard Henderson } 374330878590SRichard Henderson save_gpr(ctx, a->t, dest); 37440b1347d2SRichard Henderson 37450b1347d2SRichard Henderson /* Install the new nullification. */ 37460b1347d2SRichard Henderson cond_free(&ctx->null_cond); 374730878590SRichard Henderson if (a->c) { 3748bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37490b1347d2SRichard Henderson } 375031234768SRichard Henderson return nullify_end(ctx); 37510b1347d2SRichard Henderson } 37520b1347d2SRichard Henderson 375372ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 37540b1347d2SRichard Henderson { 375572ae4f2bSRichard Henderson unsigned len, width; 3756c53e401eSRichard Henderson uint64_t mask0, mask1; 37576fd0c7bcSRichard Henderson TCGv_i64 dest; 37580b1347d2SRichard Henderson 375972ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 376072ae4f2bSRichard Henderson return false; 376172ae4f2bSRichard Henderson } 376230878590SRichard Henderson if (a->c) { 37630b1347d2SRichard Henderson nullify_over(ctx); 37640b1347d2SRichard Henderson } 376572ae4f2bSRichard Henderson 376672ae4f2bSRichard Henderson len = a->len; 376772ae4f2bSRichard Henderson width = a->d ? 64 : 32; 376872ae4f2bSRichard Henderson if (a->cpos + len > width) { 376972ae4f2bSRichard Henderson len = width - a->cpos; 37700b1347d2SRichard Henderson } 37710b1347d2SRichard Henderson 377230878590SRichard Henderson dest = dest_gpr(ctx, a->t); 377330878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 377430878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 37750b1347d2SRichard Henderson 377630878590SRichard Henderson if (a->nz) { 37776fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 37786fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 37796fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 37800b1347d2SRichard Henderson } else { 37816fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 37820b1347d2SRichard Henderson } 378330878590SRichard Henderson save_gpr(ctx, a->t, dest); 37840b1347d2SRichard Henderson 37850b1347d2SRichard Henderson /* Install the new nullification. */ 37860b1347d2SRichard Henderson cond_free(&ctx->null_cond); 378730878590SRichard Henderson if (a->c) { 378872ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37890b1347d2SRichard Henderson } 379031234768SRichard Henderson return nullify_end(ctx); 37910b1347d2SRichard Henderson } 37920b1347d2SRichard Henderson 379372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 37940b1347d2SRichard Henderson { 379530878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 379672ae4f2bSRichard Henderson unsigned len, width; 37976fd0c7bcSRichard Henderson TCGv_i64 dest, val; 37980b1347d2SRichard Henderson 379972ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 380072ae4f2bSRichard Henderson return false; 380172ae4f2bSRichard Henderson } 380230878590SRichard Henderson if (a->c) { 38030b1347d2SRichard Henderson nullify_over(ctx); 38040b1347d2SRichard Henderson } 380572ae4f2bSRichard Henderson 380672ae4f2bSRichard Henderson len = a->len; 380772ae4f2bSRichard Henderson width = a->d ? 64 : 32; 380872ae4f2bSRichard Henderson if (a->cpos + len > width) { 380972ae4f2bSRichard Henderson len = width - a->cpos; 38100b1347d2SRichard Henderson } 38110b1347d2SRichard Henderson 381230878590SRichard Henderson dest = dest_gpr(ctx, a->t); 381330878590SRichard Henderson val = load_gpr(ctx, a->r); 38140b1347d2SRichard Henderson if (rs == 0) { 38156fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 38160b1347d2SRichard Henderson } else { 38176fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 38180b1347d2SRichard Henderson } 381930878590SRichard Henderson save_gpr(ctx, a->t, dest); 38200b1347d2SRichard Henderson 38210b1347d2SRichard Henderson /* Install the new nullification. */ 38220b1347d2SRichard Henderson cond_free(&ctx->null_cond); 382330878590SRichard Henderson if (a->c) { 382472ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 38250b1347d2SRichard Henderson } 382631234768SRichard Henderson return nullify_end(ctx); 38270b1347d2SRichard Henderson } 38280b1347d2SRichard Henderson 382972ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 38306fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 38310b1347d2SRichard Henderson { 38320b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 383372ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 38346fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3835c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 38360b1347d2SRichard Henderson 38370b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3838aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3839aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 38400b1347d2SRichard Henderson 38410b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 38426fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 38436fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 38440b1347d2SRichard Henderson 3845aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 38466fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 38476fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 38480b1347d2SRichard Henderson if (rs) { 38496fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 38506fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 38516fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 38526fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 38530b1347d2SRichard Henderson } else { 38546fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 38550b1347d2SRichard Henderson } 38560b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 38570b1347d2SRichard Henderson 38580b1347d2SRichard Henderson /* Install the new nullification. */ 38590b1347d2SRichard Henderson cond_free(&ctx->null_cond); 38600b1347d2SRichard Henderson if (c) { 386172ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 38620b1347d2SRichard Henderson } 386331234768SRichard Henderson return nullify_end(ctx); 38640b1347d2SRichard Henderson } 38650b1347d2SRichard Henderson 386672ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 386730878590SRichard Henderson { 386872ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 386972ae4f2bSRichard Henderson return false; 387072ae4f2bSRichard Henderson } 3871a6deecceSSven Schnelle if (a->c) { 3872a6deecceSSven Schnelle nullify_over(ctx); 3873a6deecceSSven Schnelle } 387472ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 387572ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 387630878590SRichard Henderson } 387730878590SRichard Henderson 387872ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 387930878590SRichard Henderson { 388072ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 388172ae4f2bSRichard Henderson return false; 388272ae4f2bSRichard Henderson } 3883a6deecceSSven Schnelle if (a->c) { 3884a6deecceSSven Schnelle nullify_over(ctx); 3885a6deecceSSven Schnelle } 388672ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 38876fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 388830878590SRichard Henderson } 38890b1347d2SRichard Henderson 38908340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 389198cd9ca7SRichard Henderson { 3892019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY 3893bc921866SRichard Henderson ctx->iaq_j.space = tcg_temp_new_i64(); 3894bc921866SRichard Henderson load_spr(ctx, ctx->iaq_j.space, a->sp); 3895c301f34eSRichard Henderson #endif 3896019f4159SRichard Henderson 3897bc921866SRichard Henderson ctx->iaq_j.base = tcg_temp_new_i64(); 3898bc921866SRichard Henderson ctx->iaq_j.disp = 0; 3899bc921866SRichard Henderson 3900bc921866SRichard Henderson tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp); 3901bc921866SRichard Henderson ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base); 3902bc921866SRichard Henderson 3903bc921866SRichard Henderson return do_ibranch(ctx, a->l, true, a->n); 390498cd9ca7SRichard Henderson } 390598cd9ca7SRichard Henderson 39068340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 390798cd9ca7SRichard Henderson { 39082644f80bSRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 390998cd9ca7SRichard Henderson } 391098cd9ca7SRichard Henderson 39118340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 391243e05652SRichard Henderson { 3913bc921866SRichard Henderson int64_t disp = a->disp; 391443e05652SRichard Henderson 39156e5f5300SSven Schnelle nullify_over(ctx); 39166e5f5300SSven Schnelle 391743e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 391843e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 391943e05652SRichard Henderson * expensive to track. Real hardware will trap for 392043e05652SRichard Henderson * b gateway 392143e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 392243e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 392343e05652SRichard Henderson * diagnose the security hole 392443e05652SRichard Henderson * b gateway 392543e05652SRichard Henderson * b evil 392643e05652SRichard Henderson * in which instructions at evil would run with increased privs. 392743e05652SRichard Henderson */ 3928bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 392943e05652SRichard Henderson return gen_illegal(ctx); 393043e05652SRichard Henderson } 393143e05652SRichard Henderson 393243e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 393343e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 393494956d7bSPhilippe Mathieu-Daudé int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next); 393543e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 393643e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 393743e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 393843e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 393943e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 394043e05652SRichard Henderson if (type < 0) { 394131234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 394231234768SRichard Henderson return true; 394343e05652SRichard Henderson } 394443e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 394543e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 3946bc921866SRichard Henderson disp -= ctx->privilege; 3947bc921866SRichard Henderson disp += type - 4; 394843e05652SRichard Henderson } 394943e05652SRichard Henderson } else { 3950bc921866SRichard Henderson disp -= ctx->privilege; /* priv = 0 */ 395143e05652SRichard Henderson } 395243e05652SRichard Henderson #endif 395343e05652SRichard Henderson 39546e5f5300SSven Schnelle if (a->l) { 39556fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 39566e5f5300SSven Schnelle if (ctx->privilege < 3) { 39576fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 39586e5f5300SSven Schnelle } 39596fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 39606e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 39616e5f5300SSven Schnelle } 39626e5f5300SSven Schnelle 3963bc921866SRichard Henderson return do_dbranch(ctx, disp, 0, a->n); 396443e05652SRichard Henderson } 396543e05652SRichard Henderson 39668340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 396798cd9ca7SRichard Henderson { 3968b35aec85SRichard Henderson if (a->x) { 3969bc921866SRichard Henderson DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8); 3970bc921866SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 3971bc921866SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3972bc921866SRichard Henderson 3973660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 3974bc921866SRichard Henderson copy_iaoq_entry(ctx, t0, &next); 3975bc921866SRichard Henderson tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3); 3976bc921866SRichard Henderson tcg_gen_add_i64(t0, t0, t1); 3977bc921866SRichard Henderson 3978bc921866SRichard Henderson ctx->iaq_j = iaqe_next_absv(ctx, t0); 3979bc921866SRichard Henderson return do_ibranch(ctx, a->l, false, a->n); 3980b35aec85SRichard Henderson } else { 3981b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 39822644f80bSRichard Henderson return do_dbranch(ctx, 0, a->l, a->n); 3983b35aec85SRichard Henderson } 398498cd9ca7SRichard Henderson } 398598cd9ca7SRichard Henderson 39868340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 398798cd9ca7SRichard Henderson { 39886fd0c7bcSRichard Henderson TCGv_i64 dest; 398998cd9ca7SRichard Henderson 39908340f534SRichard Henderson if (a->x == 0) { 39918340f534SRichard Henderson dest = load_gpr(ctx, a->b); 399298cd9ca7SRichard Henderson } else { 3993aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 39946fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 39956fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 399698cd9ca7SRichard Henderson } 3997660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 3998bc921866SRichard Henderson ctx->iaq_j = iaqe_next_absv(ctx, dest); 3999bc921866SRichard Henderson 4000bc921866SRichard Henderson return do_ibranch(ctx, 0, false, a->n); 400198cd9ca7SRichard Henderson } 400298cd9ca7SRichard Henderson 40038340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 400498cd9ca7SRichard Henderson { 4005019f4159SRichard Henderson TCGv_i64 b = load_gpr(ctx, a->b); 400698cd9ca7SRichard Henderson 4007019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY 4008bc921866SRichard Henderson ctx->iaq_j.space = space_select(ctx, 0, b); 4009c301f34eSRichard Henderson #endif 4010bc921866SRichard Henderson ctx->iaq_j.base = do_ibranch_priv(ctx, b); 4011bc921866SRichard Henderson ctx->iaq_j.disp = 0; 4012019f4159SRichard Henderson 4013bc921866SRichard Henderson return do_ibranch(ctx, a->l, false, a->n); 401498cd9ca7SRichard Henderson } 401598cd9ca7SRichard Henderson 4016a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 4017a8966ba7SRichard Henderson { 4018a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 4019a8966ba7SRichard Henderson return ctx->is_pa20; 4020a8966ba7SRichard Henderson } 4021a8966ba7SRichard Henderson 40221ca74648SRichard Henderson /* 40231ca74648SRichard Henderson * Float class 0 40241ca74648SRichard Henderson */ 4025ebe9383cSRichard Henderson 40261ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4027ebe9383cSRichard Henderson { 4028ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 4029ebe9383cSRichard Henderson } 4030ebe9383cSRichard Henderson 403159f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 403259f8c04bSHelge Deller { 4033a300dad3SRichard Henderson uint64_t ret; 4034a300dad3SRichard Henderson 4035c53e401eSRichard Henderson if (ctx->is_pa20) { 4036a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 4037a300dad3SRichard Henderson } else { 4038a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 4039a300dad3SRichard Henderson } 4040a300dad3SRichard Henderson 404159f8c04bSHelge Deller nullify_over(ctx); 4042a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 404359f8c04bSHelge Deller return nullify_end(ctx); 404459f8c04bSHelge Deller } 404559f8c04bSHelge Deller 40461ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 40471ca74648SRichard Henderson { 40481ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 40491ca74648SRichard Henderson } 40501ca74648SRichard Henderson 4051ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4052ebe9383cSRichard Henderson { 4053ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 4054ebe9383cSRichard Henderson } 4055ebe9383cSRichard Henderson 40561ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 40571ca74648SRichard Henderson { 40581ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 40591ca74648SRichard Henderson } 40601ca74648SRichard Henderson 40611ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4062ebe9383cSRichard Henderson { 4063ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 4064ebe9383cSRichard Henderson } 4065ebe9383cSRichard Henderson 40661ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 40671ca74648SRichard Henderson { 40681ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 40691ca74648SRichard Henderson } 40701ca74648SRichard Henderson 4071ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4072ebe9383cSRichard Henderson { 4073ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 4074ebe9383cSRichard Henderson } 4075ebe9383cSRichard Henderson 40761ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 40771ca74648SRichard Henderson { 40781ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 40791ca74648SRichard Henderson } 40801ca74648SRichard Henderson 40811ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 40821ca74648SRichard Henderson { 40831ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 40841ca74648SRichard Henderson } 40851ca74648SRichard Henderson 40861ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 40871ca74648SRichard Henderson { 40881ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 40891ca74648SRichard Henderson } 40901ca74648SRichard Henderson 40911ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 40921ca74648SRichard Henderson { 40931ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 40941ca74648SRichard Henderson } 40951ca74648SRichard Henderson 40961ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 40971ca74648SRichard Henderson { 40981ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 40991ca74648SRichard Henderson } 41001ca74648SRichard Henderson 41011ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4102ebe9383cSRichard Henderson { 4103ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 4104ebe9383cSRichard Henderson } 4105ebe9383cSRichard Henderson 41061ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 41071ca74648SRichard Henderson { 41081ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 41091ca74648SRichard Henderson } 41101ca74648SRichard Henderson 4111ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4112ebe9383cSRichard Henderson { 4113ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 4114ebe9383cSRichard Henderson } 4115ebe9383cSRichard Henderson 41161ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 41171ca74648SRichard Henderson { 41181ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 41191ca74648SRichard Henderson } 41201ca74648SRichard Henderson 41211ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4122ebe9383cSRichard Henderson { 4123ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 4124ebe9383cSRichard Henderson } 4125ebe9383cSRichard Henderson 41261ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 41271ca74648SRichard Henderson { 41281ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 41291ca74648SRichard Henderson } 41301ca74648SRichard Henderson 4131ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4132ebe9383cSRichard Henderson { 4133ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4134ebe9383cSRichard Henderson } 4135ebe9383cSRichard Henderson 41361ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 41371ca74648SRichard Henderson { 41381ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 41391ca74648SRichard Henderson } 41401ca74648SRichard Henderson 41411ca74648SRichard Henderson /* 41421ca74648SRichard Henderson * Float class 1 41431ca74648SRichard Henderson */ 41441ca74648SRichard Henderson 41451ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 41461ca74648SRichard Henderson { 41471ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 41481ca74648SRichard Henderson } 41491ca74648SRichard Henderson 41501ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 41511ca74648SRichard Henderson { 41521ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 41531ca74648SRichard Henderson } 41541ca74648SRichard Henderson 41551ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 41561ca74648SRichard Henderson { 41571ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 41581ca74648SRichard Henderson } 41591ca74648SRichard Henderson 41601ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 41611ca74648SRichard Henderson { 41621ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 41631ca74648SRichard Henderson } 41641ca74648SRichard Henderson 41651ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 41661ca74648SRichard Henderson { 41671ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 41681ca74648SRichard Henderson } 41691ca74648SRichard Henderson 41701ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 41711ca74648SRichard Henderson { 41721ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 41731ca74648SRichard Henderson } 41741ca74648SRichard Henderson 41751ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 41761ca74648SRichard Henderson { 41771ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 41781ca74648SRichard Henderson } 41791ca74648SRichard Henderson 41801ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 41811ca74648SRichard Henderson { 41821ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 41831ca74648SRichard Henderson } 41841ca74648SRichard Henderson 41851ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 41861ca74648SRichard Henderson { 41871ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 41881ca74648SRichard Henderson } 41891ca74648SRichard Henderson 41901ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 41911ca74648SRichard Henderson { 41921ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 41931ca74648SRichard Henderson } 41941ca74648SRichard Henderson 41951ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 41961ca74648SRichard Henderson { 41971ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 41981ca74648SRichard Henderson } 41991ca74648SRichard Henderson 42001ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 42011ca74648SRichard Henderson { 42021ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 42031ca74648SRichard Henderson } 42041ca74648SRichard Henderson 42051ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 42061ca74648SRichard Henderson { 42071ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 42081ca74648SRichard Henderson } 42091ca74648SRichard Henderson 42101ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 42111ca74648SRichard Henderson { 42121ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 42131ca74648SRichard Henderson } 42141ca74648SRichard Henderson 42151ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 42161ca74648SRichard Henderson { 42171ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 42181ca74648SRichard Henderson } 42191ca74648SRichard Henderson 42201ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 42211ca74648SRichard Henderson { 42221ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 42231ca74648SRichard Henderson } 42241ca74648SRichard Henderson 42251ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 42261ca74648SRichard Henderson { 42271ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 42281ca74648SRichard Henderson } 42291ca74648SRichard Henderson 42301ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 42311ca74648SRichard Henderson { 42321ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 42331ca74648SRichard Henderson } 42341ca74648SRichard Henderson 42351ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 42361ca74648SRichard Henderson { 42371ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 42381ca74648SRichard Henderson } 42391ca74648SRichard Henderson 42401ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 42411ca74648SRichard Henderson { 42421ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 42431ca74648SRichard Henderson } 42441ca74648SRichard Henderson 42451ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 42461ca74648SRichard Henderson { 42471ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 42481ca74648SRichard Henderson } 42491ca74648SRichard Henderson 42501ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 42511ca74648SRichard Henderson { 42521ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 42531ca74648SRichard Henderson } 42541ca74648SRichard Henderson 42551ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 42561ca74648SRichard Henderson { 42571ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 42581ca74648SRichard Henderson } 42591ca74648SRichard Henderson 42601ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 42611ca74648SRichard Henderson { 42621ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 42631ca74648SRichard Henderson } 42641ca74648SRichard Henderson 42651ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 42661ca74648SRichard Henderson { 42671ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 42681ca74648SRichard Henderson } 42691ca74648SRichard Henderson 42701ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 42711ca74648SRichard Henderson { 42721ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 42731ca74648SRichard Henderson } 42741ca74648SRichard Henderson 42751ca74648SRichard Henderson /* 42761ca74648SRichard Henderson * Float class 2 42771ca74648SRichard Henderson */ 42781ca74648SRichard Henderson 42791ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4280ebe9383cSRichard Henderson { 4281ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4282ebe9383cSRichard Henderson 4283ebe9383cSRichard Henderson nullify_over(ctx); 4284ebe9383cSRichard Henderson 42851ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 42861ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 428729dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 428829dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4289ebe9383cSRichard Henderson 4290ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4291ebe9383cSRichard Henderson 42921ca74648SRichard Henderson return nullify_end(ctx); 4293ebe9383cSRichard Henderson } 4294ebe9383cSRichard Henderson 42951ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4296ebe9383cSRichard Henderson { 4297ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4298ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4299ebe9383cSRichard Henderson 4300ebe9383cSRichard Henderson nullify_over(ctx); 4301ebe9383cSRichard Henderson 43021ca74648SRichard Henderson ta = load_frd0(a->r1); 43031ca74648SRichard Henderson tb = load_frd0(a->r2); 430429dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 430529dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4306ebe9383cSRichard Henderson 4307ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4308ebe9383cSRichard Henderson 430931234768SRichard Henderson return nullify_end(ctx); 4310ebe9383cSRichard Henderson } 4311ebe9383cSRichard Henderson 43121ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4313ebe9383cSRichard Henderson { 43146fd0c7bcSRichard Henderson TCGv_i64 t; 4315ebe9383cSRichard Henderson 4316ebe9383cSRichard Henderson nullify_over(ctx); 4317ebe9383cSRichard Henderson 4318aac0f603SRichard Henderson t = tcg_temp_new_i64(); 43196fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4320ebe9383cSRichard Henderson 43211ca74648SRichard Henderson if (a->y == 1) { 4322ebe9383cSRichard Henderson int mask; 4323ebe9383cSRichard Henderson bool inv = false; 4324ebe9383cSRichard Henderson 43251ca74648SRichard Henderson switch (a->c) { 4326ebe9383cSRichard Henderson case 0: /* simple */ 43276fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 43284c42fd0dSRichard Henderson ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0); 4329ebe9383cSRichard Henderson goto done; 4330ebe9383cSRichard Henderson case 2: /* rej */ 4331ebe9383cSRichard Henderson inv = true; 4332ebe9383cSRichard Henderson /* fallthru */ 4333ebe9383cSRichard Henderson case 1: /* acc */ 4334ebe9383cSRichard Henderson mask = 0x43ff800; 4335ebe9383cSRichard Henderson break; 4336ebe9383cSRichard Henderson case 6: /* rej8 */ 4337ebe9383cSRichard Henderson inv = true; 4338ebe9383cSRichard Henderson /* fallthru */ 4339ebe9383cSRichard Henderson case 5: /* acc8 */ 4340ebe9383cSRichard Henderson mask = 0x43f8000; 4341ebe9383cSRichard Henderson break; 4342ebe9383cSRichard Henderson case 9: /* acc6 */ 4343ebe9383cSRichard Henderson mask = 0x43e0000; 4344ebe9383cSRichard Henderson break; 4345ebe9383cSRichard Henderson case 13: /* acc4 */ 4346ebe9383cSRichard Henderson mask = 0x4380000; 4347ebe9383cSRichard Henderson break; 4348ebe9383cSRichard Henderson case 17: /* acc2 */ 4349ebe9383cSRichard Henderson mask = 0x4200000; 4350ebe9383cSRichard Henderson break; 4351ebe9383cSRichard Henderson default: 43521ca74648SRichard Henderson gen_illegal(ctx); 43531ca74648SRichard Henderson return true; 4354ebe9383cSRichard Henderson } 4355ebe9383cSRichard Henderson if (inv) { 43566fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 43576fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 43584c42fd0dSRichard Henderson ctx->null_cond = cond_make_tt(TCG_COND_EQ, t, c); 4359ebe9383cSRichard Henderson } else { 43606fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 43614c42fd0dSRichard Henderson ctx->null_cond = cond_make_ti(TCG_COND_EQ, t, 0); 4362ebe9383cSRichard Henderson } 43631ca74648SRichard Henderson } else { 43641ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 43651ca74648SRichard Henderson 43666fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 43674c42fd0dSRichard Henderson ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0); 43681ca74648SRichard Henderson } 43691ca74648SRichard Henderson 4370ebe9383cSRichard Henderson done: 437131234768SRichard Henderson return nullify_end(ctx); 4372ebe9383cSRichard Henderson } 4373ebe9383cSRichard Henderson 43741ca74648SRichard Henderson /* 43751ca74648SRichard Henderson * Float class 2 43761ca74648SRichard Henderson */ 43771ca74648SRichard Henderson 43781ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4379ebe9383cSRichard Henderson { 43801ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 43811ca74648SRichard Henderson } 43821ca74648SRichard Henderson 43831ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 43841ca74648SRichard Henderson { 43851ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 43861ca74648SRichard Henderson } 43871ca74648SRichard Henderson 43881ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 43891ca74648SRichard Henderson { 43901ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 43911ca74648SRichard Henderson } 43921ca74648SRichard Henderson 43931ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 43941ca74648SRichard Henderson { 43951ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 43961ca74648SRichard Henderson } 43971ca74648SRichard Henderson 43981ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 43991ca74648SRichard Henderson { 44001ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 44011ca74648SRichard Henderson } 44021ca74648SRichard Henderson 44031ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 44041ca74648SRichard Henderson { 44051ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 44061ca74648SRichard Henderson } 44071ca74648SRichard Henderson 44081ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 44091ca74648SRichard Henderson { 44101ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 44111ca74648SRichard Henderson } 44121ca74648SRichard Henderson 44131ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 44141ca74648SRichard Henderson { 44151ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 44161ca74648SRichard Henderson } 44171ca74648SRichard Henderson 44181ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 44191ca74648SRichard Henderson { 44201ca74648SRichard Henderson TCGv_i64 x, y; 4421ebe9383cSRichard Henderson 4422ebe9383cSRichard Henderson nullify_over(ctx); 4423ebe9383cSRichard Henderson 44241ca74648SRichard Henderson x = load_frw0_i64(a->r1); 44251ca74648SRichard Henderson y = load_frw0_i64(a->r2); 44261ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 44271ca74648SRichard Henderson save_frd(a->t, x); 4428ebe9383cSRichard Henderson 442931234768SRichard Henderson return nullify_end(ctx); 4430ebe9383cSRichard Henderson } 4431ebe9383cSRichard Henderson 4432ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4433ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4434ebe9383cSRichard Henderson { 4435ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4436ebe9383cSRichard Henderson } 4437ebe9383cSRichard Henderson 4438b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4439ebe9383cSRichard Henderson { 4440b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4441b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4442b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4443b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4444b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4445ebe9383cSRichard Henderson 4446ebe9383cSRichard Henderson nullify_over(ctx); 4447ebe9383cSRichard Henderson 4448ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4449ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4450ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4451ebe9383cSRichard Henderson 445231234768SRichard Henderson return nullify_end(ctx); 4453ebe9383cSRichard Henderson } 4454ebe9383cSRichard Henderson 4455b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4456b1e2af57SRichard Henderson { 4457b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4458b1e2af57SRichard Henderson } 4459b1e2af57SRichard Henderson 4460b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4461b1e2af57SRichard Henderson { 4462b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4463b1e2af57SRichard Henderson } 4464b1e2af57SRichard Henderson 4465b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4466b1e2af57SRichard Henderson { 4467b1e2af57SRichard Henderson nullify_over(ctx); 4468b1e2af57SRichard Henderson 4469b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4470b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4471b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4472b1e2af57SRichard Henderson 4473b1e2af57SRichard Henderson return nullify_end(ctx); 4474b1e2af57SRichard Henderson } 4475b1e2af57SRichard Henderson 4476b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4477b1e2af57SRichard Henderson { 4478b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4479b1e2af57SRichard Henderson } 4480b1e2af57SRichard Henderson 4481b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4482b1e2af57SRichard Henderson { 4483b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4484b1e2af57SRichard Henderson } 4485b1e2af57SRichard Henderson 4486c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4487ebe9383cSRichard Henderson { 4488c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4489ebe9383cSRichard Henderson 4490ebe9383cSRichard Henderson nullify_over(ctx); 4491c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4492c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4493c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4494ebe9383cSRichard Henderson 4495c3bad4f8SRichard Henderson if (a->neg) { 4496ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4497ebe9383cSRichard Henderson } else { 4498ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4499ebe9383cSRichard Henderson } 4500ebe9383cSRichard Henderson 4501c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 450231234768SRichard Henderson return nullify_end(ctx); 4503ebe9383cSRichard Henderson } 4504ebe9383cSRichard Henderson 4505c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4506ebe9383cSRichard Henderson { 4507c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4508ebe9383cSRichard Henderson 4509ebe9383cSRichard Henderson nullify_over(ctx); 4510c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4511c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4512c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4513ebe9383cSRichard Henderson 4514c3bad4f8SRichard Henderson if (a->neg) { 4515ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4516ebe9383cSRichard Henderson } else { 4517ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4518ebe9383cSRichard Henderson } 4519ebe9383cSRichard Henderson 4520c3bad4f8SRichard Henderson save_frd(a->t, x); 452131234768SRichard Henderson return nullify_end(ctx); 4522ebe9383cSRichard Henderson } 4523ebe9383cSRichard Henderson 452438193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */ 452538193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a) 452615da177bSSven Schnelle { 4527cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4528cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4529ad75a51eSRichard Henderson nullify_over(ctx); 4530ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4531cf6b28d4SHelge Deller return nullify_end(ctx); 453238193127SRichard Henderson #endif 453315da177bSSven Schnelle } 453438193127SRichard Henderson 453538193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */ 453638193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a) 453738193127SRichard Henderson { 453838193127SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 453938193127SRichard Henderson #ifndef CONFIG_USER_ONLY 4540dbca0835SHelge Deller nullify_over(ctx); 4541dbca0835SHelge Deller gen_helper_diag_console_output(tcg_env); 4542dbca0835SHelge Deller return nullify_end(ctx); 4543ad75a51eSRichard Henderson #endif 454438193127SRichard Henderson } 454538193127SRichard Henderson 45463bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a) 45473bdf2081SHelge Deller { 45483bdf2081SHelge Deller return !ctx->is_pa20 && do_getshadowregs(ctx); 45493bdf2081SHelge Deller } 45503bdf2081SHelge Deller 45513bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a) 45523bdf2081SHelge Deller { 45533bdf2081SHelge Deller return ctx->is_pa20 && do_getshadowregs(ctx); 45543bdf2081SHelge Deller } 45553bdf2081SHelge Deller 45563bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a) 45573bdf2081SHelge Deller { 45583bdf2081SHelge Deller return !ctx->is_pa20 && do_putshadowregs(ctx); 45593bdf2081SHelge Deller } 45603bdf2081SHelge Deller 45613bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a) 45623bdf2081SHelge Deller { 45633bdf2081SHelge Deller return ctx->is_pa20 && do_putshadowregs(ctx); 45643bdf2081SHelge Deller } 45653bdf2081SHelge Deller 456638193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a) 456738193127SRichard Henderson { 456838193127SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4569ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4570ad75a51eSRichard Henderson return true; 4571ad75a51eSRichard Henderson } 457215da177bSSven Schnelle 4573b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 457461766fe9SRichard Henderson { 457551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4576f764718dSRichard Henderson int bound; 457761766fe9SRichard Henderson 457851b061fbSRichard Henderson ctx->cs = cs; 4579494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4580bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 45813d68ee7bSRichard Henderson 45823d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4583c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 45843d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 45850d89cb7cSRichard Henderson ctx->iaoq_first = ctx->base.pc_first | ctx->privilege; 45860d89cb7cSRichard Henderson ctx->iaq_b.disp = ctx->base.tb->cs_base - ctx->base.pc_first; 4587217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4588c301f34eSRichard Henderson #else 4589494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4590bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4591bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4592451d993dSRichard Henderson : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX); 45933d68ee7bSRichard Henderson 4594c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4595c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4596c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4597c301f34eSRichard Henderson int32_t diff = cs_base; 4598c301f34eSRichard Henderson 45990d89cb7cSRichard Henderson ctx->iaoq_first = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 46000d89cb7cSRichard Henderson 4601bc921866SRichard Henderson if (diff) { 46020d89cb7cSRichard Henderson ctx->iaq_b.disp = diff; 4603bc921866SRichard Henderson } else { 4604bc921866SRichard Henderson ctx->iaq_b.base = cpu_iaoq_b; 4605bc921866SRichard Henderson ctx->iaq_b.space = cpu_iasq_b; 4606bc921866SRichard Henderson } 4607c301f34eSRichard Henderson #endif 460861766fe9SRichard Henderson 4609a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4610a4db4a78SRichard Henderson 46113d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 46123d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4613b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 461461766fe9SRichard Henderson } 461561766fe9SRichard Henderson 461651b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 461751b061fbSRichard Henderson { 461851b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 461961766fe9SRichard Henderson 46203d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 462151b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 462251b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4623494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 462451b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 462551b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4626129e9cc3SRichard Henderson } 462751b061fbSRichard Henderson ctx->null_lab = NULL; 462861766fe9SRichard Henderson } 462961766fe9SRichard Henderson 463051b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 463151b061fbSRichard Henderson { 463251b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 463351b061fbSRichard Henderson 4634bc921866SRichard Henderson tcg_debug_assert(!iaqe_variable(&ctx->iaq_f)); 46350d89cb7cSRichard Henderson tcg_gen_insn_start(ctx->iaoq_first + ctx->iaq_f.disp, 46360d89cb7cSRichard Henderson (iaqe_variable(&ctx->iaq_b) ? -1 : 46370d89cb7cSRichard Henderson ctx->iaoq_first + ctx->iaq_b.disp), 0); 463824638bd1SRichard Henderson ctx->insn_start_updated = false; 463951b061fbSRichard Henderson } 464051b061fbSRichard Henderson 464151b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 464251b061fbSRichard Henderson { 464351b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4644b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 464551b061fbSRichard Henderson DisasJumpType ret; 464651b061fbSRichard Henderson 464751b061fbSRichard Henderson /* Execute one insn. */ 4648ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4649c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 465031234768SRichard Henderson do_page_zero(ctx); 465131234768SRichard Henderson ret = ctx->base.is_jmp; 4652869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4653ba1d0b44SRichard Henderson } else 4654ba1d0b44SRichard Henderson #endif 4655ba1d0b44SRichard Henderson { 465661766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 465761766fe9SRichard Henderson the page permissions for execute. */ 46584e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 465961766fe9SRichard Henderson 4660bc921866SRichard Henderson /* 4661bc921866SRichard Henderson * Set up the IA queue for the next insn. 4662bc921866SRichard Henderson * This will be overwritten by a branch. 4663bc921866SRichard Henderson */ 4664bc921866SRichard Henderson ctx->iaq_n = NULL; 4665bc921866SRichard Henderson memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j)); 466661766fe9SRichard Henderson 466751b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 466851b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4669869051eaSRichard Henderson ret = DISAS_NEXT; 4670129e9cc3SRichard Henderson } else { 46711a19da0dSRichard Henderson ctx->insn = insn; 467231274b46SRichard Henderson if (!decode(ctx, insn)) { 467331274b46SRichard Henderson gen_illegal(ctx); 467431274b46SRichard Henderson } 467531234768SRichard Henderson ret = ctx->base.is_jmp; 467651b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4677129e9cc3SRichard Henderson } 467861766fe9SRichard Henderson } 467961766fe9SRichard Henderson 4680dbdccbdfSRichard Henderson /* If the TranslationBlock must end, do so. */ 4681dbdccbdfSRichard Henderson ctx->base.pc_next += 4; 4682dbdccbdfSRichard Henderson if (ret != DISAS_NEXT) { 4683dbdccbdfSRichard Henderson return; 468461766fe9SRichard Henderson } 4685dbdccbdfSRichard Henderson /* Note this also detects a priority change. */ 4686bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) 4687bc921866SRichard Henderson || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 4688dbdccbdfSRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 4689dbdccbdfSRichard Henderson return; 4690129e9cc3SRichard Henderson } 4691dbdccbdfSRichard Henderson 4692dbdccbdfSRichard Henderson /* 4693dbdccbdfSRichard Henderson * Advance the insn queue. 4694dbdccbdfSRichard Henderson * The only exit now is DISAS_TOO_MANY from the translator loop. 4695dbdccbdfSRichard Henderson */ 4696bc921866SRichard Henderson ctx->iaq_f.disp = ctx->iaq_b.disp; 4697bc921866SRichard Henderson if (!ctx->iaq_n) { 4698bc921866SRichard Henderson ctx->iaq_b.disp += 4; 4699bc921866SRichard Henderson return; 4700bc921866SRichard Henderson } 4701bc921866SRichard Henderson /* 4702bc921866SRichard Henderson * If IAQ_Next is variable in any way, we need to copy into the 4703bc921866SRichard Henderson * IAQ_Back globals, in case the next insn raises an exception. 4704bc921866SRichard Henderson */ 4705bc921866SRichard Henderson if (ctx->iaq_n->base) { 4706bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n); 4707bc921866SRichard Henderson ctx->iaq_b.base = cpu_iaoq_b; 4708bc921866SRichard Henderson ctx->iaq_b.disp = 0; 47090dcd6640SRichard Henderson } else { 4710bc921866SRichard Henderson ctx->iaq_b.disp = ctx->iaq_n->disp; 47110dcd6640SRichard Henderson } 4712bc921866SRichard Henderson if (ctx->iaq_n->space) { 4713bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space); 4714bc921866SRichard Henderson ctx->iaq_b.space = cpu_iasq_b; 4715142faf5fSRichard Henderson } 471661766fe9SRichard Henderson } 471761766fe9SRichard Henderson 471851b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 471951b061fbSRichard Henderson { 472051b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4721e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 4722dbdccbdfSRichard Henderson /* Assume the insn queue has not been advanced. */ 4723bc921866SRichard Henderson DisasIAQE *f = &ctx->iaq_b; 4724bc921866SRichard Henderson DisasIAQE *b = ctx->iaq_n; 472551b061fbSRichard Henderson 4726e1b5a5edSRichard Henderson switch (is_jmp) { 4727869051eaSRichard Henderson case DISAS_NORETURN: 472861766fe9SRichard Henderson break; 472951b061fbSRichard Henderson case DISAS_TOO_MANY: 4730dbdccbdfSRichard Henderson /* The insn queue has not been advanced. */ 4731bc921866SRichard Henderson f = &ctx->iaq_f; 4732bc921866SRichard Henderson b = &ctx->iaq_b; 473361766fe9SRichard Henderson /* FALLTHRU */ 4734dbdccbdfSRichard Henderson case DISAS_IAQ_N_STALE: 4735bc921866SRichard Henderson if (use_goto_tb(ctx, f, b) 4736dbdccbdfSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4737dbdccbdfSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 4738dbdccbdfSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 4739bc921866SRichard Henderson gen_goto_tb(ctx, 0, f, b); 47408532a14eSRichard Henderson break; 474161766fe9SRichard Henderson } 4742c5d0aec2SRichard Henderson /* FALLTHRU */ 4743dbdccbdfSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4744bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 4745dbdccbdfSRichard Henderson nullify_save(ctx); 4746dbdccbdfSRichard Henderson if (is_jmp == DISAS_IAQ_N_STALE_EXIT) { 4747dbdccbdfSRichard Henderson tcg_gen_exit_tb(NULL, 0); 4748dbdccbdfSRichard Henderson break; 4749dbdccbdfSRichard Henderson } 4750dbdccbdfSRichard Henderson /* FALLTHRU */ 4751dbdccbdfSRichard Henderson case DISAS_IAQ_N_UPDATED: 4752dbdccbdfSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 4753dbdccbdfSRichard Henderson break; 4754c5d0aec2SRichard Henderson case DISAS_EXIT: 4755c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 475661766fe9SRichard Henderson break; 475761766fe9SRichard Henderson default: 475851b061fbSRichard Henderson g_assert_not_reached(); 475961766fe9SRichard Henderson } 476051b061fbSRichard Henderson } 476161766fe9SRichard Henderson 47628eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 47638eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 476451b061fbSRichard Henderson { 4765c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 476661766fe9SRichard Henderson 4767ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4768ba1d0b44SRichard Henderson switch (pc) { 47697ad439dfSRichard Henderson case 0x00: 47708eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4771ba1d0b44SRichard Henderson return; 47727ad439dfSRichard Henderson case 0xb0: 47738eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4774ba1d0b44SRichard Henderson return; 47757ad439dfSRichard Henderson case 0xe0: 47768eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4777ba1d0b44SRichard Henderson return; 47787ad439dfSRichard Henderson case 0x100: 47798eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4780ba1d0b44SRichard Henderson return; 47817ad439dfSRichard Henderson } 4782ba1d0b44SRichard Henderson #endif 4783ba1d0b44SRichard Henderson 47848eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 47858eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 478661766fe9SRichard Henderson } 478751b061fbSRichard Henderson 478851b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 478951b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 479051b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 479151b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 479251b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 479351b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 479451b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 479551b061fbSRichard Henderson }; 479651b061fbSRichard Henderson 4797597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 479832f0c394SAnton Johansson vaddr pc, void *host_pc) 479951b061fbSRichard Henderson { 4800bc921866SRichard Henderson DisasContext ctx = { }; 4801306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 480261766fe9SRichard Henderson } 4803