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 1010*25f97be7SRichard 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 142346bb3d46SRichard Henderson tcg_gen_andi_i64(cb, cb, test_cb); 14244c42fd0dSRichard Henderson cond = cond_make_ti(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, cb, 0); 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 { 35196fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 352001afb7beSRichard Henderson DisasCond cond; 35211e9ab9fbSRichard Henderson int p; 352201afb7beSRichard Henderson 352301afb7beSRichard Henderson nullify_over(ctx); 352401afb7beSRichard Henderson 3525aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 352601afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 352782d0c831SRichard Henderson p = a->p | (a->d ? 0 : 32); 35286fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, tcg_r, p); 352901afb7beSRichard Henderson 35304c42fd0dSRichard Henderson cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0); 353101afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 353201afb7beSRichard Henderson } 353301afb7beSRichard Henderson 353401afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 353501afb7beSRichard Henderson { 35366fd0c7bcSRichard Henderson TCGv_i64 dest; 353798cd9ca7SRichard Henderson DisasCond cond; 353898cd9ca7SRichard Henderson 353998cd9ca7SRichard Henderson nullify_over(ctx); 354098cd9ca7SRichard Henderson 354101afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 354201afb7beSRichard Henderson if (a->r1 == 0) { 35436fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 354498cd9ca7SRichard Henderson } else { 35456fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 354698cd9ca7SRichard Henderson } 354798cd9ca7SRichard Henderson 35484fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 35494fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 355001afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 355101afb7beSRichard Henderson } 355201afb7beSRichard Henderson 355301afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 355401afb7beSRichard Henderson { 35556fd0c7bcSRichard Henderson TCGv_i64 dest; 355601afb7beSRichard Henderson DisasCond cond; 355701afb7beSRichard Henderson 355801afb7beSRichard Henderson nullify_over(ctx); 355901afb7beSRichard Henderson 356001afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 35616fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 356201afb7beSRichard Henderson 35634fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 35644fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 356501afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 356698cd9ca7SRichard Henderson } 356798cd9ca7SRichard Henderson 3568f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 35690b1347d2SRichard Henderson { 35706fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 35710b1347d2SRichard Henderson 3572f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3573f7b775a9SRichard Henderson return false; 3574f7b775a9SRichard Henderson } 357530878590SRichard Henderson if (a->c) { 35760b1347d2SRichard Henderson nullify_over(ctx); 35770b1347d2SRichard Henderson } 35780b1347d2SRichard Henderson 357930878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3580f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 358130878590SRichard Henderson if (a->r1 == 0) { 3582f7b775a9SRichard Henderson if (a->d) { 35836fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3584f7b775a9SRichard Henderson } else { 3585aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3586f7b775a9SRichard Henderson 35876fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 35886fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 35896fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3590f7b775a9SRichard Henderson } 359130878590SRichard Henderson } else if (a->r1 == a->r2) { 3592f7b775a9SRichard Henderson if (a->d) { 35936fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3594f7b775a9SRichard Henderson } else { 35950b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3596e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3597e1d635e8SRichard Henderson 35986fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 35996fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3600f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3601e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 36026fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3603f7b775a9SRichard Henderson } 3604f7b775a9SRichard Henderson } else { 36056fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3606f7b775a9SRichard Henderson 3607f7b775a9SRichard Henderson if (a->d) { 3608aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3609aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3610f7b775a9SRichard Henderson 36116fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 3612a01491a2SHelge Deller tcg_gen_shl_i64(t, src1, n); 36136fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 3614a01491a2SHelge Deller tcg_gen_shr_i64(dest, src2, cpu_sar); 36156fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 36160b1347d2SRichard Henderson } else { 36170b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 36180b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 36190b1347d2SRichard Henderson 36206fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3621967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3622967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 36230b1347d2SRichard Henderson } 3624f7b775a9SRichard Henderson } 362530878590SRichard Henderson save_gpr(ctx, a->t, dest); 36260b1347d2SRichard Henderson 36270b1347d2SRichard Henderson /* Install the new nullification. */ 36280b1347d2SRichard Henderson cond_free(&ctx->null_cond); 362930878590SRichard Henderson if (a->c) { 3630d37fad0aSSven Schnelle ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36310b1347d2SRichard Henderson } 363231234768SRichard Henderson return nullify_end(ctx); 36330b1347d2SRichard Henderson } 36340b1347d2SRichard Henderson 3635f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 36360b1347d2SRichard Henderson { 3637f7b775a9SRichard Henderson unsigned width, sa; 36386fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 36390b1347d2SRichard Henderson 3640f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3641f7b775a9SRichard Henderson return false; 3642f7b775a9SRichard Henderson } 364330878590SRichard Henderson if (a->c) { 36440b1347d2SRichard Henderson nullify_over(ctx); 36450b1347d2SRichard Henderson } 36460b1347d2SRichard Henderson 3647f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3648f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3649f7b775a9SRichard Henderson 365030878590SRichard Henderson dest = dest_gpr(ctx, a->t); 365130878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 365205bfd4dbSRichard Henderson if (a->r1 == 0) { 36536fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3654c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 36556fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3656f7b775a9SRichard Henderson } else { 3657f7b775a9SRichard Henderson assert(!a->d); 3658f7b775a9SRichard Henderson if (a->r1 == a->r2) { 36590b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 36606fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 36610b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 36626fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 36630b1347d2SRichard Henderson } else { 3664967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3665967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 36660b1347d2SRichard Henderson } 3667f7b775a9SRichard Henderson } 366830878590SRichard Henderson save_gpr(ctx, a->t, dest); 36690b1347d2SRichard Henderson 36700b1347d2SRichard Henderson /* Install the new nullification. */ 36710b1347d2SRichard Henderson cond_free(&ctx->null_cond); 367230878590SRichard Henderson if (a->c) { 3673d37fad0aSSven Schnelle ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36740b1347d2SRichard Henderson } 367531234768SRichard Henderson return nullify_end(ctx); 36760b1347d2SRichard Henderson } 36770b1347d2SRichard Henderson 3678bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 36790b1347d2SRichard Henderson { 3680bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 36816fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 36820b1347d2SRichard Henderson 3683bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3684bd792da3SRichard Henderson return false; 3685bd792da3SRichard Henderson } 368630878590SRichard Henderson if (a->c) { 36870b1347d2SRichard Henderson nullify_over(ctx); 36880b1347d2SRichard Henderson } 36890b1347d2SRichard Henderson 369030878590SRichard Henderson dest = dest_gpr(ctx, a->t); 369130878590SRichard Henderson src = load_gpr(ctx, a->r); 3692aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 36930b1347d2SRichard Henderson 36940b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 36956fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 36966fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3697d781cb77SRichard Henderson 369830878590SRichard Henderson if (a->se) { 3699bd792da3SRichard Henderson if (!a->d) { 37006fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3701bd792da3SRichard Henderson src = dest; 3702bd792da3SRichard Henderson } 37036fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 37046fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 37050b1347d2SRichard Henderson } else { 3706bd792da3SRichard Henderson if (!a->d) { 37076fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3708bd792da3SRichard Henderson src = dest; 3709bd792da3SRichard Henderson } 37106fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 37116fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 37120b1347d2SRichard Henderson } 371330878590SRichard Henderson save_gpr(ctx, a->t, dest); 37140b1347d2SRichard Henderson 37150b1347d2SRichard Henderson /* Install the new nullification. */ 37160b1347d2SRichard Henderson cond_free(&ctx->null_cond); 371730878590SRichard Henderson if (a->c) { 3718bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37190b1347d2SRichard Henderson } 372031234768SRichard Henderson return nullify_end(ctx); 37210b1347d2SRichard Henderson } 37220b1347d2SRichard Henderson 3723bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 37240b1347d2SRichard Henderson { 3725bd792da3SRichard Henderson unsigned len, cpos, width; 37266fd0c7bcSRichard Henderson TCGv_i64 dest, src; 37270b1347d2SRichard Henderson 3728bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3729bd792da3SRichard Henderson return false; 3730bd792da3SRichard Henderson } 373130878590SRichard Henderson if (a->c) { 37320b1347d2SRichard Henderson nullify_over(ctx); 37330b1347d2SRichard Henderson } 37340b1347d2SRichard Henderson 3735bd792da3SRichard Henderson len = a->len; 3736bd792da3SRichard Henderson width = a->d ? 64 : 32; 3737bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3738bd792da3SRichard Henderson if (cpos + len > width) { 3739bd792da3SRichard Henderson len = width - cpos; 3740bd792da3SRichard Henderson } 3741bd792da3SRichard Henderson 374230878590SRichard Henderson dest = dest_gpr(ctx, a->t); 374330878590SRichard Henderson src = load_gpr(ctx, a->r); 374430878590SRichard Henderson if (a->se) { 37456fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 37460b1347d2SRichard Henderson } else { 37476fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 37480b1347d2SRichard Henderson } 374930878590SRichard Henderson save_gpr(ctx, a->t, dest); 37500b1347d2SRichard Henderson 37510b1347d2SRichard Henderson /* Install the new nullification. */ 37520b1347d2SRichard Henderson cond_free(&ctx->null_cond); 375330878590SRichard Henderson if (a->c) { 3754bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37550b1347d2SRichard Henderson } 375631234768SRichard Henderson return nullify_end(ctx); 37570b1347d2SRichard Henderson } 37580b1347d2SRichard Henderson 375972ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 37600b1347d2SRichard Henderson { 376172ae4f2bSRichard Henderson unsigned len, width; 3762c53e401eSRichard Henderson uint64_t mask0, mask1; 37636fd0c7bcSRichard Henderson TCGv_i64 dest; 37640b1347d2SRichard Henderson 376572ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 376672ae4f2bSRichard Henderson return false; 376772ae4f2bSRichard Henderson } 376830878590SRichard Henderson if (a->c) { 37690b1347d2SRichard Henderson nullify_over(ctx); 37700b1347d2SRichard Henderson } 377172ae4f2bSRichard Henderson 377272ae4f2bSRichard Henderson len = a->len; 377372ae4f2bSRichard Henderson width = a->d ? 64 : 32; 377472ae4f2bSRichard Henderson if (a->cpos + len > width) { 377572ae4f2bSRichard Henderson len = width - a->cpos; 37760b1347d2SRichard Henderson } 37770b1347d2SRichard Henderson 377830878590SRichard Henderson dest = dest_gpr(ctx, a->t); 377930878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 378030878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 37810b1347d2SRichard Henderson 378230878590SRichard Henderson if (a->nz) { 37836fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 37846fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 37856fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 37860b1347d2SRichard Henderson } else { 37876fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 37880b1347d2SRichard Henderson } 378930878590SRichard Henderson save_gpr(ctx, a->t, dest); 37900b1347d2SRichard Henderson 37910b1347d2SRichard Henderson /* Install the new nullification. */ 37920b1347d2SRichard Henderson cond_free(&ctx->null_cond); 379330878590SRichard Henderson if (a->c) { 379472ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37950b1347d2SRichard Henderson } 379631234768SRichard Henderson return nullify_end(ctx); 37970b1347d2SRichard Henderson } 37980b1347d2SRichard Henderson 379972ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 38000b1347d2SRichard Henderson { 380130878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 380272ae4f2bSRichard Henderson unsigned len, width; 38036fd0c7bcSRichard Henderson TCGv_i64 dest, val; 38040b1347d2SRichard Henderson 380572ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 380672ae4f2bSRichard Henderson return false; 380772ae4f2bSRichard Henderson } 380830878590SRichard Henderson if (a->c) { 38090b1347d2SRichard Henderson nullify_over(ctx); 38100b1347d2SRichard Henderson } 381172ae4f2bSRichard Henderson 381272ae4f2bSRichard Henderson len = a->len; 381372ae4f2bSRichard Henderson width = a->d ? 64 : 32; 381472ae4f2bSRichard Henderson if (a->cpos + len > width) { 381572ae4f2bSRichard Henderson len = width - a->cpos; 38160b1347d2SRichard Henderson } 38170b1347d2SRichard Henderson 381830878590SRichard Henderson dest = dest_gpr(ctx, a->t); 381930878590SRichard Henderson val = load_gpr(ctx, a->r); 38200b1347d2SRichard Henderson if (rs == 0) { 38216fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 38220b1347d2SRichard Henderson } else { 38236fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 38240b1347d2SRichard Henderson } 382530878590SRichard Henderson save_gpr(ctx, a->t, dest); 38260b1347d2SRichard Henderson 38270b1347d2SRichard Henderson /* Install the new nullification. */ 38280b1347d2SRichard Henderson cond_free(&ctx->null_cond); 382930878590SRichard Henderson if (a->c) { 383072ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 38310b1347d2SRichard Henderson } 383231234768SRichard Henderson return nullify_end(ctx); 38330b1347d2SRichard Henderson } 38340b1347d2SRichard Henderson 383572ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 38366fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 38370b1347d2SRichard Henderson { 38380b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 383972ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 38406fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3841c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 38420b1347d2SRichard Henderson 38430b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3844aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3845aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 38460b1347d2SRichard Henderson 38470b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 38486fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 38496fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 38500b1347d2SRichard Henderson 3851aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 38526fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 38536fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 38540b1347d2SRichard Henderson if (rs) { 38556fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 38566fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 38576fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 38586fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 38590b1347d2SRichard Henderson } else { 38606fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 38610b1347d2SRichard Henderson } 38620b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 38630b1347d2SRichard Henderson 38640b1347d2SRichard Henderson /* Install the new nullification. */ 38650b1347d2SRichard Henderson cond_free(&ctx->null_cond); 38660b1347d2SRichard Henderson if (c) { 386772ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 38680b1347d2SRichard Henderson } 386931234768SRichard Henderson return nullify_end(ctx); 38700b1347d2SRichard Henderson } 38710b1347d2SRichard Henderson 387272ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 387330878590SRichard Henderson { 387472ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 387572ae4f2bSRichard Henderson return false; 387672ae4f2bSRichard Henderson } 3877a6deecceSSven Schnelle if (a->c) { 3878a6deecceSSven Schnelle nullify_over(ctx); 3879a6deecceSSven Schnelle } 388072ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 388172ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 388230878590SRichard Henderson } 388330878590SRichard Henderson 388472ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 388530878590SRichard Henderson { 388672ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 388772ae4f2bSRichard Henderson return false; 388872ae4f2bSRichard Henderson } 3889a6deecceSSven Schnelle if (a->c) { 3890a6deecceSSven Schnelle nullify_over(ctx); 3891a6deecceSSven Schnelle } 389272ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 38936fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 389430878590SRichard Henderson } 38950b1347d2SRichard Henderson 38968340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 389798cd9ca7SRichard Henderson { 3898019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY 3899bc921866SRichard Henderson ctx->iaq_j.space = tcg_temp_new_i64(); 3900bc921866SRichard Henderson load_spr(ctx, ctx->iaq_j.space, a->sp); 3901c301f34eSRichard Henderson #endif 3902019f4159SRichard Henderson 3903bc921866SRichard Henderson ctx->iaq_j.base = tcg_temp_new_i64(); 3904bc921866SRichard Henderson ctx->iaq_j.disp = 0; 3905bc921866SRichard Henderson 3906bc921866SRichard Henderson tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp); 3907bc921866SRichard Henderson ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base); 3908bc921866SRichard Henderson 3909bc921866SRichard Henderson return do_ibranch(ctx, a->l, true, a->n); 391098cd9ca7SRichard Henderson } 391198cd9ca7SRichard Henderson 39128340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 391398cd9ca7SRichard Henderson { 39142644f80bSRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 391598cd9ca7SRichard Henderson } 391698cd9ca7SRichard Henderson 39178340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 391843e05652SRichard Henderson { 3919bc921866SRichard Henderson int64_t disp = a->disp; 392043e05652SRichard Henderson 39216e5f5300SSven Schnelle nullify_over(ctx); 39226e5f5300SSven Schnelle 392343e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 392443e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 392543e05652SRichard Henderson * expensive to track. Real hardware will trap for 392643e05652SRichard Henderson * b gateway 392743e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 392843e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 392943e05652SRichard Henderson * diagnose the security hole 393043e05652SRichard Henderson * b gateway 393143e05652SRichard Henderson * b evil 393243e05652SRichard Henderson * in which instructions at evil would run with increased privs. 393343e05652SRichard Henderson */ 3934bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 393543e05652SRichard Henderson return gen_illegal(ctx); 393643e05652SRichard Henderson } 393743e05652SRichard Henderson 393843e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 393943e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 394094956d7bSPhilippe Mathieu-Daudé int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next); 394143e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 394243e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 394343e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 394443e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 394543e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 394643e05652SRichard Henderson if (type < 0) { 394731234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 394831234768SRichard Henderson return true; 394943e05652SRichard Henderson } 395043e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 395143e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 3952bc921866SRichard Henderson disp -= ctx->privilege; 3953bc921866SRichard Henderson disp += type - 4; 395443e05652SRichard Henderson } 395543e05652SRichard Henderson } else { 3956bc921866SRichard Henderson disp -= ctx->privilege; /* priv = 0 */ 395743e05652SRichard Henderson } 395843e05652SRichard Henderson #endif 395943e05652SRichard Henderson 39606e5f5300SSven Schnelle if (a->l) { 39616fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 39626e5f5300SSven Schnelle if (ctx->privilege < 3) { 39636fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 39646e5f5300SSven Schnelle } 39656fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 39666e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 39676e5f5300SSven Schnelle } 39686e5f5300SSven Schnelle 3969bc921866SRichard Henderson return do_dbranch(ctx, disp, 0, a->n); 397043e05652SRichard Henderson } 397143e05652SRichard Henderson 39728340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 397398cd9ca7SRichard Henderson { 3974b35aec85SRichard Henderson if (a->x) { 3975bc921866SRichard Henderson DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8); 3976bc921866SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 3977bc921866SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3978bc921866SRichard Henderson 3979660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 3980bc921866SRichard Henderson copy_iaoq_entry(ctx, t0, &next); 3981bc921866SRichard Henderson tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3); 3982bc921866SRichard Henderson tcg_gen_add_i64(t0, t0, t1); 3983bc921866SRichard Henderson 3984bc921866SRichard Henderson ctx->iaq_j = iaqe_next_absv(ctx, t0); 3985bc921866SRichard Henderson return do_ibranch(ctx, a->l, false, a->n); 3986b35aec85SRichard Henderson } else { 3987b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 39882644f80bSRichard Henderson return do_dbranch(ctx, 0, a->l, a->n); 3989b35aec85SRichard Henderson } 399098cd9ca7SRichard Henderson } 399198cd9ca7SRichard Henderson 39928340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 399398cd9ca7SRichard Henderson { 39946fd0c7bcSRichard Henderson TCGv_i64 dest; 399598cd9ca7SRichard Henderson 39968340f534SRichard Henderson if (a->x == 0) { 39978340f534SRichard Henderson dest = load_gpr(ctx, a->b); 399898cd9ca7SRichard Henderson } else { 3999aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 40006fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 40016fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 400298cd9ca7SRichard Henderson } 4003660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 4004bc921866SRichard Henderson ctx->iaq_j = iaqe_next_absv(ctx, dest); 4005bc921866SRichard Henderson 4006bc921866SRichard Henderson return do_ibranch(ctx, 0, false, a->n); 400798cd9ca7SRichard Henderson } 400898cd9ca7SRichard Henderson 40098340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 401098cd9ca7SRichard Henderson { 4011019f4159SRichard Henderson TCGv_i64 b = load_gpr(ctx, a->b); 401298cd9ca7SRichard Henderson 4013019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY 4014bc921866SRichard Henderson ctx->iaq_j.space = space_select(ctx, 0, b); 4015c301f34eSRichard Henderson #endif 4016bc921866SRichard Henderson ctx->iaq_j.base = do_ibranch_priv(ctx, b); 4017bc921866SRichard Henderson ctx->iaq_j.disp = 0; 4018019f4159SRichard Henderson 4019bc921866SRichard Henderson return do_ibranch(ctx, a->l, false, a->n); 402098cd9ca7SRichard Henderson } 402198cd9ca7SRichard Henderson 4022a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 4023a8966ba7SRichard Henderson { 4024a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 4025a8966ba7SRichard Henderson return ctx->is_pa20; 4026a8966ba7SRichard Henderson } 4027a8966ba7SRichard Henderson 40281ca74648SRichard Henderson /* 40291ca74648SRichard Henderson * Float class 0 40301ca74648SRichard Henderson */ 4031ebe9383cSRichard Henderson 40321ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4033ebe9383cSRichard Henderson { 4034ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 4035ebe9383cSRichard Henderson } 4036ebe9383cSRichard Henderson 403759f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 403859f8c04bSHelge Deller { 4039a300dad3SRichard Henderson uint64_t ret; 4040a300dad3SRichard Henderson 4041c53e401eSRichard Henderson if (ctx->is_pa20) { 4042a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 4043a300dad3SRichard Henderson } else { 4044a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 4045a300dad3SRichard Henderson } 4046a300dad3SRichard Henderson 404759f8c04bSHelge Deller nullify_over(ctx); 4048a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 404959f8c04bSHelge Deller return nullify_end(ctx); 405059f8c04bSHelge Deller } 405159f8c04bSHelge Deller 40521ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 40531ca74648SRichard Henderson { 40541ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 40551ca74648SRichard Henderson } 40561ca74648SRichard Henderson 4057ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4058ebe9383cSRichard Henderson { 4059ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 4060ebe9383cSRichard Henderson } 4061ebe9383cSRichard Henderson 40621ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 40631ca74648SRichard Henderson { 40641ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 40651ca74648SRichard Henderson } 40661ca74648SRichard Henderson 40671ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4068ebe9383cSRichard Henderson { 4069ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 4070ebe9383cSRichard Henderson } 4071ebe9383cSRichard Henderson 40721ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 40731ca74648SRichard Henderson { 40741ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 40751ca74648SRichard Henderson } 40761ca74648SRichard Henderson 4077ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4078ebe9383cSRichard Henderson { 4079ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 4080ebe9383cSRichard Henderson } 4081ebe9383cSRichard Henderson 40821ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 40831ca74648SRichard Henderson { 40841ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 40851ca74648SRichard Henderson } 40861ca74648SRichard Henderson 40871ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 40881ca74648SRichard Henderson { 40891ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 40901ca74648SRichard Henderson } 40911ca74648SRichard Henderson 40921ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 40931ca74648SRichard Henderson { 40941ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 40951ca74648SRichard Henderson } 40961ca74648SRichard Henderson 40971ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 40981ca74648SRichard Henderson { 40991ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 41001ca74648SRichard Henderson } 41011ca74648SRichard Henderson 41021ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 41031ca74648SRichard Henderson { 41041ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 41051ca74648SRichard Henderson } 41061ca74648SRichard Henderson 41071ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4108ebe9383cSRichard Henderson { 4109ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 4110ebe9383cSRichard Henderson } 4111ebe9383cSRichard Henderson 41121ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 41131ca74648SRichard Henderson { 41141ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 41151ca74648SRichard Henderson } 41161ca74648SRichard Henderson 4117ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4118ebe9383cSRichard Henderson { 4119ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 4120ebe9383cSRichard Henderson } 4121ebe9383cSRichard Henderson 41221ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 41231ca74648SRichard Henderson { 41241ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 41251ca74648SRichard Henderson } 41261ca74648SRichard Henderson 41271ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4128ebe9383cSRichard Henderson { 4129ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 4130ebe9383cSRichard Henderson } 4131ebe9383cSRichard Henderson 41321ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 41331ca74648SRichard Henderson { 41341ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 41351ca74648SRichard Henderson } 41361ca74648SRichard Henderson 4137ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4138ebe9383cSRichard Henderson { 4139ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4140ebe9383cSRichard Henderson } 4141ebe9383cSRichard Henderson 41421ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 41431ca74648SRichard Henderson { 41441ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 41451ca74648SRichard Henderson } 41461ca74648SRichard Henderson 41471ca74648SRichard Henderson /* 41481ca74648SRichard Henderson * Float class 1 41491ca74648SRichard Henderson */ 41501ca74648SRichard Henderson 41511ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 41521ca74648SRichard Henderson { 41531ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 41541ca74648SRichard Henderson } 41551ca74648SRichard Henderson 41561ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 41571ca74648SRichard Henderson { 41581ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 41591ca74648SRichard Henderson } 41601ca74648SRichard Henderson 41611ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 41621ca74648SRichard Henderson { 41631ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 41641ca74648SRichard Henderson } 41651ca74648SRichard Henderson 41661ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 41671ca74648SRichard Henderson { 41681ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 41691ca74648SRichard Henderson } 41701ca74648SRichard Henderson 41711ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 41721ca74648SRichard Henderson { 41731ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 41741ca74648SRichard Henderson } 41751ca74648SRichard Henderson 41761ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 41771ca74648SRichard Henderson { 41781ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 41791ca74648SRichard Henderson } 41801ca74648SRichard Henderson 41811ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 41821ca74648SRichard Henderson { 41831ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 41841ca74648SRichard Henderson } 41851ca74648SRichard Henderson 41861ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 41871ca74648SRichard Henderson { 41881ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 41891ca74648SRichard Henderson } 41901ca74648SRichard Henderson 41911ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 41921ca74648SRichard Henderson { 41931ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 41941ca74648SRichard Henderson } 41951ca74648SRichard Henderson 41961ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 41971ca74648SRichard Henderson { 41981ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 41991ca74648SRichard Henderson } 42001ca74648SRichard Henderson 42011ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 42021ca74648SRichard Henderson { 42031ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 42041ca74648SRichard Henderson } 42051ca74648SRichard Henderson 42061ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 42071ca74648SRichard Henderson { 42081ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 42091ca74648SRichard Henderson } 42101ca74648SRichard Henderson 42111ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 42121ca74648SRichard Henderson { 42131ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 42141ca74648SRichard Henderson } 42151ca74648SRichard Henderson 42161ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 42171ca74648SRichard Henderson { 42181ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 42191ca74648SRichard Henderson } 42201ca74648SRichard Henderson 42211ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 42221ca74648SRichard Henderson { 42231ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 42241ca74648SRichard Henderson } 42251ca74648SRichard Henderson 42261ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 42271ca74648SRichard Henderson { 42281ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 42291ca74648SRichard Henderson } 42301ca74648SRichard Henderson 42311ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 42321ca74648SRichard Henderson { 42331ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 42341ca74648SRichard Henderson } 42351ca74648SRichard Henderson 42361ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 42371ca74648SRichard Henderson { 42381ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 42391ca74648SRichard Henderson } 42401ca74648SRichard Henderson 42411ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 42421ca74648SRichard Henderson { 42431ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 42441ca74648SRichard Henderson } 42451ca74648SRichard Henderson 42461ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 42471ca74648SRichard Henderson { 42481ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 42491ca74648SRichard Henderson } 42501ca74648SRichard Henderson 42511ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 42521ca74648SRichard Henderson { 42531ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 42541ca74648SRichard Henderson } 42551ca74648SRichard Henderson 42561ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 42571ca74648SRichard Henderson { 42581ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 42591ca74648SRichard Henderson } 42601ca74648SRichard Henderson 42611ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 42621ca74648SRichard Henderson { 42631ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 42641ca74648SRichard Henderson } 42651ca74648SRichard Henderson 42661ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 42671ca74648SRichard Henderson { 42681ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 42691ca74648SRichard Henderson } 42701ca74648SRichard Henderson 42711ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 42721ca74648SRichard Henderson { 42731ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 42741ca74648SRichard Henderson } 42751ca74648SRichard Henderson 42761ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 42771ca74648SRichard Henderson { 42781ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 42791ca74648SRichard Henderson } 42801ca74648SRichard Henderson 42811ca74648SRichard Henderson /* 42821ca74648SRichard Henderson * Float class 2 42831ca74648SRichard Henderson */ 42841ca74648SRichard Henderson 42851ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4286ebe9383cSRichard Henderson { 4287ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4288ebe9383cSRichard Henderson 4289ebe9383cSRichard Henderson nullify_over(ctx); 4290ebe9383cSRichard Henderson 42911ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 42921ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 429329dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 429429dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4295ebe9383cSRichard Henderson 4296ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4297ebe9383cSRichard Henderson 42981ca74648SRichard Henderson return nullify_end(ctx); 4299ebe9383cSRichard Henderson } 4300ebe9383cSRichard Henderson 43011ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4302ebe9383cSRichard Henderson { 4303ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4304ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4305ebe9383cSRichard Henderson 4306ebe9383cSRichard Henderson nullify_over(ctx); 4307ebe9383cSRichard Henderson 43081ca74648SRichard Henderson ta = load_frd0(a->r1); 43091ca74648SRichard Henderson tb = load_frd0(a->r2); 431029dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 431129dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4312ebe9383cSRichard Henderson 4313ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4314ebe9383cSRichard Henderson 431531234768SRichard Henderson return nullify_end(ctx); 4316ebe9383cSRichard Henderson } 4317ebe9383cSRichard Henderson 43181ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4319ebe9383cSRichard Henderson { 43206fd0c7bcSRichard Henderson TCGv_i64 t; 4321ebe9383cSRichard Henderson 4322ebe9383cSRichard Henderson nullify_over(ctx); 4323ebe9383cSRichard Henderson 4324aac0f603SRichard Henderson t = tcg_temp_new_i64(); 43256fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4326ebe9383cSRichard Henderson 43271ca74648SRichard Henderson if (a->y == 1) { 4328ebe9383cSRichard Henderson int mask; 4329ebe9383cSRichard Henderson bool inv = false; 4330ebe9383cSRichard Henderson 43311ca74648SRichard Henderson switch (a->c) { 4332ebe9383cSRichard Henderson case 0: /* simple */ 43336fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 43344c42fd0dSRichard Henderson ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0); 4335ebe9383cSRichard Henderson goto done; 4336ebe9383cSRichard Henderson case 2: /* rej */ 4337ebe9383cSRichard Henderson inv = true; 4338ebe9383cSRichard Henderson /* fallthru */ 4339ebe9383cSRichard Henderson case 1: /* acc */ 4340ebe9383cSRichard Henderson mask = 0x43ff800; 4341ebe9383cSRichard Henderson break; 4342ebe9383cSRichard Henderson case 6: /* rej8 */ 4343ebe9383cSRichard Henderson inv = true; 4344ebe9383cSRichard Henderson /* fallthru */ 4345ebe9383cSRichard Henderson case 5: /* acc8 */ 4346ebe9383cSRichard Henderson mask = 0x43f8000; 4347ebe9383cSRichard Henderson break; 4348ebe9383cSRichard Henderson case 9: /* acc6 */ 4349ebe9383cSRichard Henderson mask = 0x43e0000; 4350ebe9383cSRichard Henderson break; 4351ebe9383cSRichard Henderson case 13: /* acc4 */ 4352ebe9383cSRichard Henderson mask = 0x4380000; 4353ebe9383cSRichard Henderson break; 4354ebe9383cSRichard Henderson case 17: /* acc2 */ 4355ebe9383cSRichard Henderson mask = 0x4200000; 4356ebe9383cSRichard Henderson break; 4357ebe9383cSRichard Henderson default: 43581ca74648SRichard Henderson gen_illegal(ctx); 43591ca74648SRichard Henderson return true; 4360ebe9383cSRichard Henderson } 4361ebe9383cSRichard Henderson if (inv) { 43626fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 43636fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 43644c42fd0dSRichard Henderson ctx->null_cond = cond_make_tt(TCG_COND_EQ, t, c); 4365ebe9383cSRichard Henderson } else { 43666fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 43674c42fd0dSRichard Henderson ctx->null_cond = cond_make_ti(TCG_COND_EQ, t, 0); 4368ebe9383cSRichard Henderson } 43691ca74648SRichard Henderson } else { 43701ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 43711ca74648SRichard Henderson 43726fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 43734c42fd0dSRichard Henderson ctx->null_cond = cond_make_ti(TCG_COND_NE, t, 0); 43741ca74648SRichard Henderson } 43751ca74648SRichard Henderson 4376ebe9383cSRichard Henderson done: 437731234768SRichard Henderson return nullify_end(ctx); 4378ebe9383cSRichard Henderson } 4379ebe9383cSRichard Henderson 43801ca74648SRichard Henderson /* 43811ca74648SRichard Henderson * Float class 2 43821ca74648SRichard Henderson */ 43831ca74648SRichard Henderson 43841ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4385ebe9383cSRichard Henderson { 43861ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 43871ca74648SRichard Henderson } 43881ca74648SRichard Henderson 43891ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 43901ca74648SRichard Henderson { 43911ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 43921ca74648SRichard Henderson } 43931ca74648SRichard Henderson 43941ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 43951ca74648SRichard Henderson { 43961ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 43971ca74648SRichard Henderson } 43981ca74648SRichard Henderson 43991ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 44001ca74648SRichard Henderson { 44011ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 44021ca74648SRichard Henderson } 44031ca74648SRichard Henderson 44041ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 44051ca74648SRichard Henderson { 44061ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 44071ca74648SRichard Henderson } 44081ca74648SRichard Henderson 44091ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 44101ca74648SRichard Henderson { 44111ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 44121ca74648SRichard Henderson } 44131ca74648SRichard Henderson 44141ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 44151ca74648SRichard Henderson { 44161ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 44171ca74648SRichard Henderson } 44181ca74648SRichard Henderson 44191ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 44201ca74648SRichard Henderson { 44211ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 44221ca74648SRichard Henderson } 44231ca74648SRichard Henderson 44241ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 44251ca74648SRichard Henderson { 44261ca74648SRichard Henderson TCGv_i64 x, y; 4427ebe9383cSRichard Henderson 4428ebe9383cSRichard Henderson nullify_over(ctx); 4429ebe9383cSRichard Henderson 44301ca74648SRichard Henderson x = load_frw0_i64(a->r1); 44311ca74648SRichard Henderson y = load_frw0_i64(a->r2); 44321ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 44331ca74648SRichard Henderson save_frd(a->t, x); 4434ebe9383cSRichard Henderson 443531234768SRichard Henderson return nullify_end(ctx); 4436ebe9383cSRichard Henderson } 4437ebe9383cSRichard Henderson 4438ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4439ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4440ebe9383cSRichard Henderson { 4441ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4442ebe9383cSRichard Henderson } 4443ebe9383cSRichard Henderson 4444b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4445ebe9383cSRichard Henderson { 4446b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4447b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4448b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4449b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4450b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4451ebe9383cSRichard Henderson 4452ebe9383cSRichard Henderson nullify_over(ctx); 4453ebe9383cSRichard Henderson 4454ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4455ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4456ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4457ebe9383cSRichard Henderson 445831234768SRichard Henderson return nullify_end(ctx); 4459ebe9383cSRichard Henderson } 4460ebe9383cSRichard Henderson 4461b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4462b1e2af57SRichard Henderson { 4463b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4464b1e2af57SRichard Henderson } 4465b1e2af57SRichard Henderson 4466b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4467b1e2af57SRichard Henderson { 4468b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4469b1e2af57SRichard Henderson } 4470b1e2af57SRichard Henderson 4471b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4472b1e2af57SRichard Henderson { 4473b1e2af57SRichard Henderson nullify_over(ctx); 4474b1e2af57SRichard Henderson 4475b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4476b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4477b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4478b1e2af57SRichard Henderson 4479b1e2af57SRichard Henderson return nullify_end(ctx); 4480b1e2af57SRichard Henderson } 4481b1e2af57SRichard Henderson 4482b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4483b1e2af57SRichard Henderson { 4484b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4485b1e2af57SRichard Henderson } 4486b1e2af57SRichard Henderson 4487b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4488b1e2af57SRichard Henderson { 4489b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4490b1e2af57SRichard Henderson } 4491b1e2af57SRichard Henderson 4492c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4493ebe9383cSRichard Henderson { 4494c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4495ebe9383cSRichard Henderson 4496ebe9383cSRichard Henderson nullify_over(ctx); 4497c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4498c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4499c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4500ebe9383cSRichard Henderson 4501c3bad4f8SRichard Henderson if (a->neg) { 4502ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4503ebe9383cSRichard Henderson } else { 4504ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4505ebe9383cSRichard Henderson } 4506ebe9383cSRichard Henderson 4507c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 450831234768SRichard Henderson return nullify_end(ctx); 4509ebe9383cSRichard Henderson } 4510ebe9383cSRichard Henderson 4511c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4512ebe9383cSRichard Henderson { 4513c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4514ebe9383cSRichard Henderson 4515ebe9383cSRichard Henderson nullify_over(ctx); 4516c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4517c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4518c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4519ebe9383cSRichard Henderson 4520c3bad4f8SRichard Henderson if (a->neg) { 4521ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4522ebe9383cSRichard Henderson } else { 4523ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4524ebe9383cSRichard Henderson } 4525ebe9383cSRichard Henderson 4526c3bad4f8SRichard Henderson save_frd(a->t, x); 452731234768SRichard Henderson return nullify_end(ctx); 4528ebe9383cSRichard Henderson } 4529ebe9383cSRichard Henderson 453038193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */ 453138193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a) 453215da177bSSven Schnelle { 4533cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4534cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4535ad75a51eSRichard Henderson nullify_over(ctx); 4536ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4537cf6b28d4SHelge Deller return nullify_end(ctx); 453838193127SRichard Henderson #endif 453915da177bSSven Schnelle } 454038193127SRichard Henderson 454138193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */ 454238193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a) 454338193127SRichard Henderson { 454438193127SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 454538193127SRichard Henderson #ifndef CONFIG_USER_ONLY 4546dbca0835SHelge Deller nullify_over(ctx); 4547dbca0835SHelge Deller gen_helper_diag_console_output(tcg_env); 4548dbca0835SHelge Deller return nullify_end(ctx); 4549ad75a51eSRichard Henderson #endif 455038193127SRichard Henderson } 455138193127SRichard Henderson 45523bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a) 45533bdf2081SHelge Deller { 45543bdf2081SHelge Deller return !ctx->is_pa20 && do_getshadowregs(ctx); 45553bdf2081SHelge Deller } 45563bdf2081SHelge Deller 45573bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a) 45583bdf2081SHelge Deller { 45593bdf2081SHelge Deller return ctx->is_pa20 && do_getshadowregs(ctx); 45603bdf2081SHelge Deller } 45613bdf2081SHelge Deller 45623bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a) 45633bdf2081SHelge Deller { 45643bdf2081SHelge Deller return !ctx->is_pa20 && do_putshadowregs(ctx); 45653bdf2081SHelge Deller } 45663bdf2081SHelge Deller 45673bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a) 45683bdf2081SHelge Deller { 45693bdf2081SHelge Deller return ctx->is_pa20 && do_putshadowregs(ctx); 45703bdf2081SHelge Deller } 45713bdf2081SHelge Deller 457238193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a) 457338193127SRichard Henderson { 457438193127SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4575ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4576ad75a51eSRichard Henderson return true; 4577ad75a51eSRichard Henderson } 457815da177bSSven Schnelle 4579b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 458061766fe9SRichard Henderson { 458151b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4582f764718dSRichard Henderson int bound; 458361766fe9SRichard Henderson 458451b061fbSRichard Henderson ctx->cs = cs; 4585494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4586bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 45873d68ee7bSRichard Henderson 45883d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4589c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 45903d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 45910d89cb7cSRichard Henderson ctx->iaoq_first = ctx->base.pc_first | ctx->privilege; 45920d89cb7cSRichard Henderson ctx->iaq_b.disp = ctx->base.tb->cs_base - ctx->base.pc_first; 4593217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4594c301f34eSRichard Henderson #else 4595494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4596bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4597bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4598451d993dSRichard Henderson : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX); 45993d68ee7bSRichard Henderson 4600c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4601c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4602c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4603c301f34eSRichard Henderson int32_t diff = cs_base; 4604c301f34eSRichard Henderson 46050d89cb7cSRichard Henderson ctx->iaoq_first = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 46060d89cb7cSRichard Henderson 4607bc921866SRichard Henderson if (diff) { 46080d89cb7cSRichard Henderson ctx->iaq_b.disp = diff; 4609bc921866SRichard Henderson } else { 4610bc921866SRichard Henderson ctx->iaq_b.base = cpu_iaoq_b; 4611bc921866SRichard Henderson ctx->iaq_b.space = cpu_iasq_b; 4612bc921866SRichard Henderson } 4613c301f34eSRichard Henderson #endif 461461766fe9SRichard Henderson 4615a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4616a4db4a78SRichard Henderson 46173d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 46183d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4619b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 462061766fe9SRichard Henderson } 462161766fe9SRichard Henderson 462251b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 462351b061fbSRichard Henderson { 462451b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 462561766fe9SRichard Henderson 46263d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 462751b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 462851b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4629494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 463051b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 463151b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4632129e9cc3SRichard Henderson } 463351b061fbSRichard Henderson ctx->null_lab = NULL; 463461766fe9SRichard Henderson } 463561766fe9SRichard Henderson 463651b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 463751b061fbSRichard Henderson { 463851b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 463951b061fbSRichard Henderson 4640bc921866SRichard Henderson tcg_debug_assert(!iaqe_variable(&ctx->iaq_f)); 46410d89cb7cSRichard Henderson tcg_gen_insn_start(ctx->iaoq_first + ctx->iaq_f.disp, 46420d89cb7cSRichard Henderson (iaqe_variable(&ctx->iaq_b) ? -1 : 46430d89cb7cSRichard Henderson ctx->iaoq_first + ctx->iaq_b.disp), 0); 464424638bd1SRichard Henderson ctx->insn_start_updated = false; 464551b061fbSRichard Henderson } 464651b061fbSRichard Henderson 464751b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 464851b061fbSRichard Henderson { 464951b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4650b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 465151b061fbSRichard Henderson DisasJumpType ret; 465251b061fbSRichard Henderson 465351b061fbSRichard Henderson /* Execute one insn. */ 4654ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4655c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 465631234768SRichard Henderson do_page_zero(ctx); 465731234768SRichard Henderson ret = ctx->base.is_jmp; 4658869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4659ba1d0b44SRichard Henderson } else 4660ba1d0b44SRichard Henderson #endif 4661ba1d0b44SRichard Henderson { 466261766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 466361766fe9SRichard Henderson the page permissions for execute. */ 46644e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 466561766fe9SRichard Henderson 4666bc921866SRichard Henderson /* 4667bc921866SRichard Henderson * Set up the IA queue for the next insn. 4668bc921866SRichard Henderson * This will be overwritten by a branch. 4669bc921866SRichard Henderson */ 4670bc921866SRichard Henderson ctx->iaq_n = NULL; 4671bc921866SRichard Henderson memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j)); 467261766fe9SRichard Henderson 467351b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 467451b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4675869051eaSRichard Henderson ret = DISAS_NEXT; 4676129e9cc3SRichard Henderson } else { 46771a19da0dSRichard Henderson ctx->insn = insn; 467831274b46SRichard Henderson if (!decode(ctx, insn)) { 467931274b46SRichard Henderson gen_illegal(ctx); 468031274b46SRichard Henderson } 468131234768SRichard Henderson ret = ctx->base.is_jmp; 468251b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4683129e9cc3SRichard Henderson } 468461766fe9SRichard Henderson } 468561766fe9SRichard Henderson 4686dbdccbdfSRichard Henderson /* If the TranslationBlock must end, do so. */ 4687dbdccbdfSRichard Henderson ctx->base.pc_next += 4; 4688dbdccbdfSRichard Henderson if (ret != DISAS_NEXT) { 4689dbdccbdfSRichard Henderson return; 469061766fe9SRichard Henderson } 4691dbdccbdfSRichard Henderson /* Note this also detects a priority change. */ 4692bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) 4693bc921866SRichard Henderson || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 4694dbdccbdfSRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 4695dbdccbdfSRichard Henderson return; 4696129e9cc3SRichard Henderson } 4697dbdccbdfSRichard Henderson 4698dbdccbdfSRichard Henderson /* 4699dbdccbdfSRichard Henderson * Advance the insn queue. 4700dbdccbdfSRichard Henderson * The only exit now is DISAS_TOO_MANY from the translator loop. 4701dbdccbdfSRichard Henderson */ 4702bc921866SRichard Henderson ctx->iaq_f.disp = ctx->iaq_b.disp; 4703bc921866SRichard Henderson if (!ctx->iaq_n) { 4704bc921866SRichard Henderson ctx->iaq_b.disp += 4; 4705bc921866SRichard Henderson return; 4706bc921866SRichard Henderson } 4707bc921866SRichard Henderson /* 4708bc921866SRichard Henderson * If IAQ_Next is variable in any way, we need to copy into the 4709bc921866SRichard Henderson * IAQ_Back globals, in case the next insn raises an exception. 4710bc921866SRichard Henderson */ 4711bc921866SRichard Henderson if (ctx->iaq_n->base) { 4712bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n); 4713bc921866SRichard Henderson ctx->iaq_b.base = cpu_iaoq_b; 4714bc921866SRichard Henderson ctx->iaq_b.disp = 0; 47150dcd6640SRichard Henderson } else { 4716bc921866SRichard Henderson ctx->iaq_b.disp = ctx->iaq_n->disp; 47170dcd6640SRichard Henderson } 4718bc921866SRichard Henderson if (ctx->iaq_n->space) { 4719bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space); 4720bc921866SRichard Henderson ctx->iaq_b.space = cpu_iasq_b; 4721142faf5fSRichard Henderson } 472261766fe9SRichard Henderson } 472361766fe9SRichard Henderson 472451b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 472551b061fbSRichard Henderson { 472651b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4727e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 4728dbdccbdfSRichard Henderson /* Assume the insn queue has not been advanced. */ 4729bc921866SRichard Henderson DisasIAQE *f = &ctx->iaq_b; 4730bc921866SRichard Henderson DisasIAQE *b = ctx->iaq_n; 473151b061fbSRichard Henderson 4732e1b5a5edSRichard Henderson switch (is_jmp) { 4733869051eaSRichard Henderson case DISAS_NORETURN: 473461766fe9SRichard Henderson break; 473551b061fbSRichard Henderson case DISAS_TOO_MANY: 4736dbdccbdfSRichard Henderson /* The insn queue has not been advanced. */ 4737bc921866SRichard Henderson f = &ctx->iaq_f; 4738bc921866SRichard Henderson b = &ctx->iaq_b; 473961766fe9SRichard Henderson /* FALLTHRU */ 4740dbdccbdfSRichard Henderson case DISAS_IAQ_N_STALE: 4741bc921866SRichard Henderson if (use_goto_tb(ctx, f, b) 4742dbdccbdfSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4743dbdccbdfSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 4744dbdccbdfSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 4745bc921866SRichard Henderson gen_goto_tb(ctx, 0, f, b); 47468532a14eSRichard Henderson break; 474761766fe9SRichard Henderson } 4748c5d0aec2SRichard Henderson /* FALLTHRU */ 4749dbdccbdfSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4750bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 4751dbdccbdfSRichard Henderson nullify_save(ctx); 4752dbdccbdfSRichard Henderson if (is_jmp == DISAS_IAQ_N_STALE_EXIT) { 4753dbdccbdfSRichard Henderson tcg_gen_exit_tb(NULL, 0); 4754dbdccbdfSRichard Henderson break; 4755dbdccbdfSRichard Henderson } 4756dbdccbdfSRichard Henderson /* FALLTHRU */ 4757dbdccbdfSRichard Henderson case DISAS_IAQ_N_UPDATED: 4758dbdccbdfSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 4759dbdccbdfSRichard Henderson break; 4760c5d0aec2SRichard Henderson case DISAS_EXIT: 4761c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 476261766fe9SRichard Henderson break; 476361766fe9SRichard Henderson default: 476451b061fbSRichard Henderson g_assert_not_reached(); 476561766fe9SRichard Henderson } 476651b061fbSRichard Henderson } 476761766fe9SRichard Henderson 47688eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 47698eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 477051b061fbSRichard Henderson { 4771c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 477261766fe9SRichard Henderson 4773ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4774ba1d0b44SRichard Henderson switch (pc) { 47757ad439dfSRichard Henderson case 0x00: 47768eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4777ba1d0b44SRichard Henderson return; 47787ad439dfSRichard Henderson case 0xb0: 47798eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4780ba1d0b44SRichard Henderson return; 47817ad439dfSRichard Henderson case 0xe0: 47828eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4783ba1d0b44SRichard Henderson return; 47847ad439dfSRichard Henderson case 0x100: 47858eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4786ba1d0b44SRichard Henderson return; 47877ad439dfSRichard Henderson } 4788ba1d0b44SRichard Henderson #endif 4789ba1d0b44SRichard Henderson 47908eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 47918eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 479261766fe9SRichard Henderson } 479351b061fbSRichard Henderson 479451b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 479551b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 479651b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 479751b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 479851b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 479951b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 480051b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 480151b061fbSRichard Henderson }; 480251b061fbSRichard Henderson 4803597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 480432f0c394SAnton Johansson vaddr pc, void *host_pc) 480551b061fbSRichard Henderson { 4806bc921866SRichard Henderson DisasContext ctx = { }; 4807306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 480861766fe9SRichard Henderson } 4809