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 3766fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 37761766fe9SRichard Henderson { 37861766fe9SRichard Henderson if (reg == 0) { 379bc3da3cfSRichard Henderson return ctx->zero; 38061766fe9SRichard Henderson } else { 38161766fe9SRichard Henderson return cpu_gr[reg]; 38261766fe9SRichard Henderson } 38361766fe9SRichard Henderson } 38461766fe9SRichard Henderson 3856fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 38661766fe9SRichard Henderson { 387129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 388aac0f603SRichard Henderson return tcg_temp_new_i64(); 38961766fe9SRichard Henderson } else { 39061766fe9SRichard Henderson return cpu_gr[reg]; 39161766fe9SRichard Henderson } 39261766fe9SRichard Henderson } 39361766fe9SRichard Henderson 3946fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 395129e9cc3SRichard Henderson { 396129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 3976fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 398129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 399129e9cc3SRichard Henderson } else { 4006fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 401129e9cc3SRichard Henderson } 402129e9cc3SRichard Henderson } 403129e9cc3SRichard Henderson 4046fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 405129e9cc3SRichard Henderson { 406129e9cc3SRichard Henderson if (reg != 0) { 407129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 408129e9cc3SRichard Henderson } 409129e9cc3SRichard Henderson } 410129e9cc3SRichard Henderson 411e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 41296d6407fSRichard Henderson # define HI_OFS 0 41396d6407fSRichard Henderson # define LO_OFS 4 41496d6407fSRichard Henderson #else 41596d6407fSRichard Henderson # define HI_OFS 4 41696d6407fSRichard Henderson # define LO_OFS 0 41796d6407fSRichard Henderson #endif 41896d6407fSRichard Henderson 41996d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 42096d6407fSRichard Henderson { 42196d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 422ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 42396d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 42496d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 42596d6407fSRichard Henderson return ret; 42696d6407fSRichard Henderson } 42796d6407fSRichard Henderson 428ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 429ebe9383cSRichard Henderson { 430ebe9383cSRichard Henderson if (rt == 0) { 4310992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 4320992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 4330992a930SRichard Henderson return ret; 434ebe9383cSRichard Henderson } else { 435ebe9383cSRichard Henderson return load_frw_i32(rt); 436ebe9383cSRichard Henderson } 437ebe9383cSRichard Henderson } 438ebe9383cSRichard Henderson 439ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 440ebe9383cSRichard Henderson { 441ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4420992a930SRichard Henderson if (rt == 0) { 4430992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4440992a930SRichard Henderson } else { 445ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 446ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 447ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 448ebe9383cSRichard Henderson } 4490992a930SRichard Henderson return ret; 450ebe9383cSRichard Henderson } 451ebe9383cSRichard Henderson 45296d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 45396d6407fSRichard Henderson { 454ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 45596d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 45696d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 45796d6407fSRichard Henderson } 45896d6407fSRichard Henderson 45996d6407fSRichard Henderson #undef HI_OFS 46096d6407fSRichard Henderson #undef LO_OFS 46196d6407fSRichard Henderson 46296d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 46396d6407fSRichard Henderson { 46496d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 465ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 46696d6407fSRichard Henderson return ret; 46796d6407fSRichard Henderson } 46896d6407fSRichard Henderson 469ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 470ebe9383cSRichard Henderson { 471ebe9383cSRichard Henderson if (rt == 0) { 4720992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4730992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4740992a930SRichard Henderson return ret; 475ebe9383cSRichard Henderson } else { 476ebe9383cSRichard Henderson return load_frd(rt); 477ebe9383cSRichard Henderson } 478ebe9383cSRichard Henderson } 479ebe9383cSRichard Henderson 48096d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 48196d6407fSRichard Henderson { 482ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 48396d6407fSRichard Henderson } 48496d6407fSRichard Henderson 48533423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 48633423472SRichard Henderson { 48733423472SRichard Henderson #ifdef CONFIG_USER_ONLY 48833423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 48933423472SRichard Henderson #else 49033423472SRichard Henderson if (reg < 4) { 49133423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 492494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 493494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 49433423472SRichard Henderson } else { 495ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 49633423472SRichard Henderson } 49733423472SRichard Henderson #endif 49833423472SRichard Henderson } 49933423472SRichard Henderson 500129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 501129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 502129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 503129e9cc3SRichard Henderson { 504129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 505129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 506129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 507129e9cc3SRichard Henderson 508129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 509129e9cc3SRichard Henderson 510129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 5116e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 512aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 5136fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 514129e9cc3SRichard Henderson } 515129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 516129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 517129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 518129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 519129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 5206fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 521129e9cc3SRichard Henderson } 522129e9cc3SRichard Henderson 5236fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 524129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 525*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 526129e9cc3SRichard Henderson } 527129e9cc3SRichard Henderson } 528129e9cc3SRichard Henderson 529129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 530129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 531129e9cc3SRichard Henderson { 532129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 533129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 5346fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 535129e9cc3SRichard Henderson } 536129e9cc3SRichard Henderson return; 537129e9cc3SRichard Henderson } 5386e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 5396fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 540129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 541129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 542129e9cc3SRichard Henderson } 543*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 544129e9cc3SRichard Henderson } 545129e9cc3SRichard Henderson 546129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 547129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 548129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 549129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 550129e9cc3SRichard Henderson { 551129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 5526fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 553129e9cc3SRichard Henderson } 554129e9cc3SRichard Henderson } 555129e9cc3SRichard Henderson 556129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 55740f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 55840f9f908SRichard Henderson it may be tail-called from a translate function. */ 55931234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 560129e9cc3SRichard Henderson { 561129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 56231234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 563129e9cc3SRichard Henderson 564f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 565f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 566f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 567f49b3537SRichard Henderson 568129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 569129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 570129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 571129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 57231234768SRichard Henderson return true; 573129e9cc3SRichard Henderson } 574129e9cc3SRichard Henderson ctx->null_lab = NULL; 575129e9cc3SRichard Henderson 576129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 577129e9cc3SRichard Henderson /* The next instruction will be unconditional, 578129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 579129e9cc3SRichard Henderson gen_set_label(null_lab); 580129e9cc3SRichard Henderson } else { 581129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 582129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 583129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 584129e9cc3SRichard Henderson label we have the proper value in place. */ 585129e9cc3SRichard Henderson nullify_save(ctx); 586129e9cc3SRichard Henderson gen_set_label(null_lab); 587129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 588129e9cc3SRichard Henderson } 589869051eaSRichard Henderson if (status == DISAS_NORETURN) { 59031234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 591129e9cc3SRichard Henderson } 59231234768SRichard Henderson return true; 593129e9cc3SRichard Henderson } 594129e9cc3SRichard Henderson 595bc921866SRichard Henderson static bool iaqe_variable(const DisasIAQE *e) 596bc921866SRichard Henderson { 597bc921866SRichard Henderson return e->base || e->space; 598bc921866SRichard Henderson } 599bc921866SRichard Henderson 600bc921866SRichard Henderson static DisasIAQE iaqe_incr(const DisasIAQE *e, int64_t disp) 601bc921866SRichard Henderson { 602bc921866SRichard Henderson return (DisasIAQE){ 603bc921866SRichard Henderson .space = e->space, 604bc921866SRichard Henderson .base = e->base, 605bc921866SRichard Henderson .disp = e->disp + disp, 606bc921866SRichard Henderson }; 607bc921866SRichard Henderson } 608bc921866SRichard Henderson 609bc921866SRichard Henderson static DisasIAQE iaqe_branchi(DisasContext *ctx, int64_t disp) 610bc921866SRichard Henderson { 611bc921866SRichard Henderson return (DisasIAQE){ 612bc921866SRichard Henderson .space = ctx->iaq_b.space, 613bc921866SRichard Henderson .disp = ctx->iaq_f.disp + 8 + disp, 614bc921866SRichard Henderson }; 615bc921866SRichard Henderson } 616bc921866SRichard Henderson 617bc921866SRichard Henderson static DisasIAQE iaqe_next_absv(DisasContext *ctx, TCGv_i64 var) 618bc921866SRichard Henderson { 619bc921866SRichard Henderson return (DisasIAQE){ 620bc921866SRichard Henderson .space = ctx->iaq_b.space, 621bc921866SRichard Henderson .base = var, 622bc921866SRichard Henderson }; 623bc921866SRichard Henderson } 624bc921866SRichard Henderson 6256fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 626bc921866SRichard Henderson const DisasIAQE *src) 62761766fe9SRichard Henderson { 6287d50b696SSven Schnelle uint64_t mask = gva_offset_mask(ctx->tb_flags); 629f13bf343SRichard Henderson 630bc921866SRichard Henderson if (src->base == NULL) { 6310d89cb7cSRichard Henderson tcg_gen_movi_i64(dest, (ctx->iaoq_first + src->disp) & mask); 632bc921866SRichard Henderson } else if (src->disp == 0) { 633bc921866SRichard Henderson tcg_gen_andi_i64(dest, src->base, mask); 63461766fe9SRichard Henderson } else { 635bc921866SRichard Henderson tcg_gen_addi_i64(dest, src->base, src->disp); 636bc921866SRichard Henderson tcg_gen_andi_i64(dest, dest, mask); 63761766fe9SRichard Henderson } 63861766fe9SRichard Henderson } 63961766fe9SRichard Henderson 640bc921866SRichard Henderson static void install_iaq_entries(DisasContext *ctx, const DisasIAQE *f, 641bc921866SRichard Henderson const DisasIAQE *b) 64285e6cda0SRichard Henderson { 643bc921866SRichard Henderson DisasIAQE b_next; 64485e6cda0SRichard Henderson 645bc921866SRichard Henderson if (b == NULL) { 646bc921866SRichard Henderson b_next = iaqe_incr(f, 4); 647bc921866SRichard Henderson b = &b_next; 64885e6cda0SRichard Henderson } 649bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f); 650bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b); 651bc921866SRichard Henderson if (f->space) { 652bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, f->space); 653588deedaSRichard Henderson } 654bc921866SRichard Henderson if (b->space || f->space) { 655bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, b->space ? : f->space); 656588deedaSRichard Henderson } 65785e6cda0SRichard Henderson } 65885e6cda0SRichard Henderson 65943541db0SRichard Henderson static void install_link(DisasContext *ctx, unsigned link, bool with_sr0) 66043541db0SRichard Henderson { 66143541db0SRichard Henderson tcg_debug_assert(ctx->null_cond.c == TCG_COND_NEVER); 66243541db0SRichard Henderson if (!link) { 66343541db0SRichard Henderson return; 66443541db0SRichard Henderson } 6650d89cb7cSRichard Henderson DisasIAQE next = iaqe_incr(&ctx->iaq_b, 4); 6660d89cb7cSRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], &next); 66743541db0SRichard Henderson #ifndef CONFIG_USER_ONLY 66843541db0SRichard Henderson if (with_sr0) { 66943541db0SRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_b); 67043541db0SRichard Henderson } 67143541db0SRichard Henderson #endif 67243541db0SRichard Henderson } 67343541db0SRichard Henderson 67461766fe9SRichard Henderson static void gen_excp_1(int exception) 67561766fe9SRichard Henderson { 676ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 67761766fe9SRichard Henderson } 67861766fe9SRichard Henderson 67931234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 68061766fe9SRichard Henderson { 681bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_f, &ctx->iaq_b); 682129e9cc3SRichard Henderson nullify_save(ctx); 68361766fe9SRichard Henderson gen_excp_1(exception); 68431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 68561766fe9SRichard Henderson } 68661766fe9SRichard Henderson 68731234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 6881a19da0dSRichard Henderson { 68931234768SRichard Henderson nullify_over(ctx); 6906fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 691ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 69231234768SRichard Henderson gen_excp(ctx, exc); 69331234768SRichard Henderson return nullify_end(ctx); 6941a19da0dSRichard Henderson } 6951a19da0dSRichard Henderson 69631234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 69761766fe9SRichard Henderson { 69831234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 69961766fe9SRichard Henderson } 70061766fe9SRichard Henderson 70140f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 70240f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 70340f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 70440f9f908SRichard Henderson #else 705e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 706e1b5a5edSRichard Henderson do { \ 707e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 70831234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 709e1b5a5edSRichard Henderson } \ 710e1b5a5edSRichard Henderson } while (0) 71140f9f908SRichard Henderson #endif 712e1b5a5edSRichard Henderson 713bc921866SRichard Henderson static bool use_goto_tb(DisasContext *ctx, const DisasIAQE *f, 714bc921866SRichard Henderson const DisasIAQE *b) 71561766fe9SRichard Henderson { 716bc921866SRichard Henderson return (!iaqe_variable(f) && 717bc921866SRichard Henderson (b == NULL || !iaqe_variable(b)) && 7180d89cb7cSRichard Henderson translator_use_goto_tb(&ctx->base, ctx->iaoq_first + f->disp)); 71961766fe9SRichard Henderson } 72061766fe9SRichard Henderson 721129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 722129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 723129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 724129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 725129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 726129e9cc3SRichard Henderson { 727f9b11bc2SRichard Henderson return (!(tb_cflags(ctx->base.tb) & CF_BP_PAGE) 728bc921866SRichard Henderson && !iaqe_variable(&ctx->iaq_b) 7290d89cb7cSRichard Henderson && (((ctx->iaoq_first + ctx->iaq_b.disp) ^ ctx->iaoq_first) 7300d89cb7cSRichard Henderson & TARGET_PAGE_MASK) == 0); 731129e9cc3SRichard Henderson } 732129e9cc3SRichard Henderson 73361766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 734bc921866SRichard Henderson const DisasIAQE *f, const DisasIAQE *b) 73561766fe9SRichard Henderson { 736bc921866SRichard Henderson if (use_goto_tb(ctx, f, b)) { 73761766fe9SRichard Henderson tcg_gen_goto_tb(which); 738bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 73907ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 74061766fe9SRichard Henderson } else { 741bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 7427f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 74361766fe9SRichard Henderson } 74461766fe9SRichard Henderson } 74561766fe9SRichard Henderson 746b47a4a02SSven Schnelle static bool cond_need_sv(int c) 747b47a4a02SSven Schnelle { 748b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 749b47a4a02SSven Schnelle } 750b47a4a02SSven Schnelle 751b47a4a02SSven Schnelle static bool cond_need_cb(int c) 752b47a4a02SSven Schnelle { 753b47a4a02SSven Schnelle return c == 4 || c == 5; 754b47a4a02SSven Schnelle } 755b47a4a02SSven Schnelle 756b47a4a02SSven Schnelle /* 757b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 758b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 759b47a4a02SSven Schnelle */ 760b2167459SRichard Henderson 761a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 762fe2d066aSRichard Henderson TCGv_i64 res, TCGv_i64 uv, TCGv_i64 sv) 763b2167459SRichard Henderson { 764d6d46be1SRichard Henderson TCGCond sign_cond, zero_cond; 765d6d46be1SRichard Henderson uint64_t sign_imm, zero_imm; 766b2167459SRichard Henderson DisasCond cond; 7676fd0c7bcSRichard Henderson TCGv_i64 tmp; 768b2167459SRichard Henderson 769d6d46be1SRichard Henderson if (d) { 770d6d46be1SRichard Henderson /* 64-bit condition. */ 771d6d46be1SRichard Henderson sign_imm = 0; 772d6d46be1SRichard Henderson sign_cond = TCG_COND_LT; 773d6d46be1SRichard Henderson zero_imm = 0; 774d6d46be1SRichard Henderson zero_cond = TCG_COND_EQ; 775d6d46be1SRichard Henderson } else { 776d6d46be1SRichard Henderson /* 32-bit condition. */ 777d6d46be1SRichard Henderson sign_imm = 1ull << 31; 778d6d46be1SRichard Henderson sign_cond = TCG_COND_TSTNE; 779d6d46be1SRichard Henderson zero_imm = UINT32_MAX; 780d6d46be1SRichard Henderson zero_cond = TCG_COND_TSTEQ; 781d6d46be1SRichard Henderson } 782d6d46be1SRichard Henderson 783b2167459SRichard Henderson switch (cf >> 1) { 784b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 785b2167459SRichard Henderson cond = cond_make_f(); 786b2167459SRichard Henderson break; 787b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 788d6d46be1SRichard Henderson cond = cond_make_vi(zero_cond, res, zero_imm); 789b2167459SRichard Henderson break; 790b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 791aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7926fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 793d6d46be1SRichard Henderson cond = cond_make_ti(sign_cond, tmp, sign_imm); 794b2167459SRichard Henderson break; 795b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 796b47a4a02SSven Schnelle /* 797b47a4a02SSven Schnelle * Simplify: 798b47a4a02SSven Schnelle * (N ^ V) | Z 799b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 800b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 801d6d46be1SRichard Henderson * ((res ^ sv) < 0 ? 1 : !res) 802d6d46be1SRichard Henderson * !((res ^ sv) < 0 ? 0 : res) 803b47a4a02SSven Schnelle */ 804aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 805d6d46be1SRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 806d6d46be1SRichard Henderson tcg_gen_movcond_i64(sign_cond, tmp, 807d6d46be1SRichard Henderson tmp, tcg_constant_i64(sign_imm), 808d6d46be1SRichard Henderson ctx->zero, res); 809d6d46be1SRichard Henderson cond = cond_make_ti(zero_cond, tmp, zero_imm); 810b2167459SRichard Henderson break; 811fe2d066aSRichard Henderson case 4: /* NUV / UV (!UV / UV) */ 8124c42fd0dSRichard Henderson cond = cond_make_vi(TCG_COND_EQ, uv, 0); 813b2167459SRichard Henderson break; 814fe2d066aSRichard Henderson case 5: /* ZNV / VNZ (!UV | Z / UV & !Z) */ 815aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 816fe2d066aSRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, tmp, uv, ctx->zero, ctx->zero, res); 817d6d46be1SRichard Henderson cond = cond_make_ti(zero_cond, tmp, zero_imm); 818b2167459SRichard Henderson break; 819b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 820d6d46be1SRichard Henderson cond = cond_make_vi(sign_cond, sv, sign_imm); 821b2167459SRichard Henderson break; 822b2167459SRichard Henderson case 7: /* OD / EV */ 823d6d46be1SRichard Henderson cond = cond_make_vi(TCG_COND_TSTNE, res, 1); 824b2167459SRichard Henderson break; 825b2167459SRichard Henderson default: 826b2167459SRichard Henderson g_assert_not_reached(); 827b2167459SRichard Henderson } 828b2167459SRichard Henderson if (cf & 1) { 829b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 830b2167459SRichard Henderson } 831b2167459SRichard Henderson 832b2167459SRichard Henderson return cond; 833b2167459SRichard Henderson } 834b2167459SRichard Henderson 835b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 836b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 837b2167459SRichard Henderson deleted as unused. */ 838b2167459SRichard Henderson 8394fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 8406fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 8416fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 842b2167459SRichard Henderson { 8434fe9533aSRichard Henderson TCGCond tc; 8444fe9533aSRichard Henderson bool ext_uns; 845b2167459SRichard Henderson 846b2167459SRichard Henderson switch (cf >> 1) { 847b2167459SRichard Henderson case 1: /* = / <> */ 8484fe9533aSRichard Henderson tc = TCG_COND_EQ; 8494fe9533aSRichard Henderson ext_uns = true; 850b2167459SRichard Henderson break; 851b2167459SRichard Henderson case 2: /* < / >= */ 8524fe9533aSRichard Henderson tc = TCG_COND_LT; 8534fe9533aSRichard Henderson ext_uns = false; 854b2167459SRichard Henderson break; 855b2167459SRichard Henderson case 3: /* <= / > */ 8564fe9533aSRichard Henderson tc = TCG_COND_LE; 8574fe9533aSRichard Henderson ext_uns = false; 858b2167459SRichard Henderson break; 859b2167459SRichard Henderson case 4: /* << / >>= */ 8604fe9533aSRichard Henderson tc = TCG_COND_LTU; 8614fe9533aSRichard Henderson ext_uns = true; 862b2167459SRichard Henderson break; 863b2167459SRichard Henderson case 5: /* <<= / >> */ 8644fe9533aSRichard Henderson tc = TCG_COND_LEU; 8654fe9533aSRichard Henderson ext_uns = true; 866b2167459SRichard Henderson break; 867b2167459SRichard Henderson default: 868a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 869b2167459SRichard Henderson } 870b2167459SRichard Henderson 8714fe9533aSRichard Henderson if (cf & 1) { 8724fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 8734fe9533aSRichard Henderson } 87482d0c831SRichard Henderson if (!d) { 875aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 876aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 8774fe9533aSRichard Henderson 8784fe9533aSRichard Henderson if (ext_uns) { 8796fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 8806fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 8814fe9533aSRichard Henderson } else { 8826fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 8836fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 8844fe9533aSRichard Henderson } 8854c42fd0dSRichard Henderson return cond_make_tt(tc, t1, t2); 8864fe9533aSRichard Henderson } 8874c42fd0dSRichard Henderson return cond_make_vv(tc, in1, in2); 888b2167459SRichard Henderson } 889b2167459SRichard Henderson 890df0232feSRichard Henderson /* 891df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 892df0232feSRichard Henderson * computed, and use of them is undefined. 893df0232feSRichard Henderson * 894df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 895df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 896df0232feSRichard Henderson * how cases c={2,3} are treated. 897df0232feSRichard Henderson */ 898b2167459SRichard Henderson 899b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 9006fd0c7bcSRichard Henderson TCGv_i64 res) 901b2167459SRichard Henderson { 902b5af8423SRichard Henderson TCGCond tc; 903fbe65c64SRichard Henderson uint64_t imm; 904a751eb31SRichard Henderson 905fbe65c64SRichard Henderson switch (cf >> 1) { 906fbe65c64SRichard Henderson case 0: /* never / always */ 907fbe65c64SRichard Henderson case 4: /* undef, C */ 908fbe65c64SRichard Henderson case 5: /* undef, C & !Z */ 909fbe65c64SRichard Henderson case 6: /* undef, V */ 910fbe65c64SRichard Henderson return cf & 1 ? cond_make_t() : cond_make_f(); 911fbe65c64SRichard Henderson case 1: /* == / <> */ 912fbe65c64SRichard Henderson tc = d ? TCG_COND_EQ : TCG_COND_TSTEQ; 913fbe65c64SRichard Henderson imm = d ? 0 : UINT32_MAX; 914b5af8423SRichard Henderson break; 915fbe65c64SRichard Henderson case 2: /* < / >= */ 916fbe65c64SRichard Henderson tc = d ? TCG_COND_LT : TCG_COND_TSTNE; 917fbe65c64SRichard Henderson imm = d ? 0 : 1ull << 31; 918b5af8423SRichard Henderson break; 919fbe65c64SRichard Henderson case 3: /* <= / > */ 920fbe65c64SRichard Henderson tc = cf & 1 ? TCG_COND_GT : TCG_COND_LE; 92182d0c831SRichard Henderson if (!d) { 922aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 9236fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 9244c42fd0dSRichard Henderson return cond_make_ti(tc, tmp, 0); 925b5af8423SRichard Henderson } 9264c42fd0dSRichard Henderson return cond_make_vi(tc, res, 0); 927fbe65c64SRichard Henderson case 7: /* OD / EV */ 928fbe65c64SRichard Henderson tc = TCG_COND_TSTNE; 929fbe65c64SRichard Henderson imm = 1; 930fbe65c64SRichard Henderson break; 931fbe65c64SRichard Henderson default: 932fbe65c64SRichard Henderson g_assert_not_reached(); 933fbe65c64SRichard Henderson } 934fbe65c64SRichard Henderson if (cf & 1) { 935fbe65c64SRichard Henderson tc = tcg_invert_cond(tc); 936fbe65c64SRichard Henderson } 937fbe65c64SRichard Henderson return cond_make_vi(tc, res, imm); 938b2167459SRichard Henderson } 939b2167459SRichard Henderson 94098cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 94198cd9ca7SRichard Henderson 9424fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 9436fd0c7bcSRichard Henderson TCGv_i64 res) 94498cd9ca7SRichard Henderson { 94598cd9ca7SRichard Henderson unsigned c, f; 94698cd9ca7SRichard Henderson 94798cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 94898cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 94998cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 95098cd9ca7SRichard Henderson c = orig & 3; 95198cd9ca7SRichard Henderson if (c == 3) { 95298cd9ca7SRichard Henderson c = 7; 95398cd9ca7SRichard Henderson } 95498cd9ca7SRichard Henderson f = (orig & 4) / 4; 95598cd9ca7SRichard Henderson 956b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 95798cd9ca7SRichard Henderson } 95898cd9ca7SRichard Henderson 95946bb3d46SRichard Henderson /* Similar, but for unit zero conditions. */ 96046bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res) 961b2167459SRichard Henderson { 96246bb3d46SRichard Henderson TCGv_i64 tmp; 963c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 96446bb3d46SRichard Henderson uint64_t ones = 0, sgns = 0; 965b2167459SRichard Henderson 966b2167459SRichard Henderson switch (cf >> 1) { 967578b8132SSven Schnelle case 1: /* SBW / NBW */ 968578b8132SSven Schnelle if (d) { 96946bb3d46SRichard Henderson ones = d_repl; 97046bb3d46SRichard Henderson sgns = d_repl << 31; 971578b8132SSven Schnelle } 972578b8132SSven Schnelle break; 973b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 97446bb3d46SRichard Henderson ones = d_repl * 0x01010101u; 97546bb3d46SRichard Henderson sgns = ones << 7; 97646bb3d46SRichard Henderson break; 97746bb3d46SRichard Henderson case 3: /* SHZ / NHZ */ 97846bb3d46SRichard Henderson ones = d_repl * 0x00010001u; 97946bb3d46SRichard Henderson sgns = ones << 15; 98046bb3d46SRichard Henderson break; 98146bb3d46SRichard Henderson } 98246bb3d46SRichard Henderson if (ones == 0) { 98346bb3d46SRichard Henderson /* Undefined, or 0/1 (never/always). */ 98446bb3d46SRichard Henderson return cf & 1 ? cond_make_t() : cond_make_f(); 98546bb3d46SRichard Henderson } 98646bb3d46SRichard Henderson 98746bb3d46SRichard Henderson /* 98846bb3d46SRichard Henderson * See hasless(v,1) from 989b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 990b2167459SRichard Henderson */ 991aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 99246bb3d46SRichard Henderson tcg_gen_subi_i64(tmp, res, ones); 9936fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 994b2167459SRichard Henderson 99525f97be7SRichard Henderson return cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE, tmp, sgns); 996b2167459SRichard Henderson } 997b2167459SRichard Henderson 9986fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 9996fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 100072ca8753SRichard Henderson { 100182d0c831SRichard Henderson if (!d) { 1002aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 10036fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 100472ca8753SRichard Henderson return t; 100572ca8753SRichard Henderson } 100672ca8753SRichard Henderson return cb_msb; 100772ca8753SRichard Henderson } 100872ca8753SRichard Henderson 10096fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 101072ca8753SRichard Henderson { 101172ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 101272ca8753SRichard Henderson } 101372ca8753SRichard Henderson 1014b2167459SRichard Henderson /* Compute signed overflow for addition. */ 10156fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 1016f8f5986eSRichard Henderson TCGv_i64 in1, TCGv_i64 in2, 1017f8f5986eSRichard Henderson TCGv_i64 orig_in1, int shift, bool d) 1018b2167459SRichard Henderson { 1019aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1020aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1021b2167459SRichard Henderson 10226fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10236fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10246fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 1025b2167459SRichard Henderson 1026f8f5986eSRichard Henderson switch (shift) { 1027f8f5986eSRichard Henderson case 0: 1028f8f5986eSRichard Henderson break; 1029f8f5986eSRichard Henderson case 1: 1030f8f5986eSRichard Henderson /* Shift left by one and compare the sign. */ 1031f8f5986eSRichard Henderson tcg_gen_add_i64(tmp, orig_in1, orig_in1); 1032f8f5986eSRichard Henderson tcg_gen_xor_i64(tmp, tmp, orig_in1); 1033f8f5986eSRichard Henderson /* Incorporate into the overflow. */ 1034f8f5986eSRichard Henderson tcg_gen_or_i64(sv, sv, tmp); 1035f8f5986eSRichard Henderson break; 1036f8f5986eSRichard Henderson default: 1037f8f5986eSRichard Henderson { 1038f8f5986eSRichard Henderson int sign_bit = d ? 63 : 31; 1039f8f5986eSRichard Henderson 1040f8f5986eSRichard Henderson /* Compare the sign against all lower bits. */ 1041f8f5986eSRichard Henderson tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1); 1042f8f5986eSRichard Henderson tcg_gen_xor_i64(tmp, tmp, orig_in1); 1043f8f5986eSRichard Henderson /* 1044f8f5986eSRichard Henderson * If one of the bits shifting into or through the sign 1045f8f5986eSRichard Henderson * differs, then we have overflow. 1046f8f5986eSRichard Henderson */ 1047f8f5986eSRichard Henderson tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift); 1048f8f5986eSRichard Henderson tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero, 1049f8f5986eSRichard Henderson tcg_constant_i64(-1), sv); 1050f8f5986eSRichard Henderson } 1051f8f5986eSRichard Henderson } 1052b2167459SRichard Henderson return sv; 1053b2167459SRichard Henderson } 1054b2167459SRichard Henderson 1055f8f5986eSRichard Henderson /* Compute unsigned overflow for addition. */ 1056f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb, 1057f8f5986eSRichard Henderson TCGv_i64 in1, int shift, bool d) 1058f8f5986eSRichard Henderson { 1059f8f5986eSRichard Henderson if (shift == 0) { 1060f8f5986eSRichard Henderson return get_carry(ctx, d, cb, cb_msb); 1061f8f5986eSRichard Henderson } else { 1062f8f5986eSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1063f8f5986eSRichard Henderson tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift); 1064f8f5986eSRichard Henderson tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb)); 1065f8f5986eSRichard Henderson return tmp; 1066f8f5986eSRichard Henderson } 1067f8f5986eSRichard Henderson } 1068f8f5986eSRichard Henderson 1069b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 10706fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 10716fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1072b2167459SRichard Henderson { 1073aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1074aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1075b2167459SRichard Henderson 10766fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10776fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10786fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 1079b2167459SRichard Henderson 1080b2167459SRichard Henderson return sv; 1081b2167459SRichard Henderson } 1082b2167459SRichard Henderson 1083f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1, 10846fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1085faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1086b2167459SRichard Henderson { 1087f8f5986eSRichard Henderson TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp; 1088b2167459SRichard Henderson unsigned c = cf >> 1; 1089b2167459SRichard Henderson DisasCond cond; 1090b2167459SRichard Henderson 1091aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1092f764718dSRichard Henderson cb = NULL; 1093f764718dSRichard Henderson cb_msb = NULL; 1094b2167459SRichard Henderson 1095f8f5986eSRichard Henderson in1 = orig_in1; 1096b2167459SRichard Henderson if (shift) { 1097aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10986fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1099b2167459SRichard Henderson in1 = tmp; 1100b2167459SRichard Henderson } 1101b2167459SRichard Henderson 1102b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1103aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1104aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1105bdcccc17SRichard Henderson 1106a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1107b2167459SRichard Henderson if (is_c) { 11086fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1109a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1110b2167459SRichard Henderson } 11116fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 11126fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1113b2167459SRichard Henderson } else { 11146fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1115b2167459SRichard Henderson if (is_c) { 11166fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1117b2167459SRichard Henderson } 1118b2167459SRichard Henderson } 1119b2167459SRichard Henderson 1120b2167459SRichard Henderson /* Compute signed overflow if required. */ 1121f764718dSRichard Henderson sv = NULL; 1122b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1123f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d); 1124b2167459SRichard Henderson if (is_tsv) { 1125bd1ad92cSSven Schnelle if (!d) { 1126bd1ad92cSSven Schnelle tcg_gen_ext32s_i64(sv, sv); 1127bd1ad92cSSven Schnelle } 1128ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1129b2167459SRichard Henderson } 1130b2167459SRichard Henderson } 1131b2167459SRichard Henderson 1132f8f5986eSRichard Henderson /* Compute unsigned overflow if required. */ 1133f8f5986eSRichard Henderson uv = NULL; 1134f8f5986eSRichard Henderson if (cond_need_cb(c)) { 1135f8f5986eSRichard Henderson uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d); 1136f8f5986eSRichard Henderson } 1137f8f5986eSRichard Henderson 1138b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1139f8f5986eSRichard Henderson cond = do_cond(ctx, cf, d, dest, uv, sv); 1140b2167459SRichard Henderson if (is_tc) { 1141aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11426fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1143ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1144b2167459SRichard Henderson } 1145b2167459SRichard Henderson 1146b2167459SRichard Henderson /* Write back the result. */ 1147b2167459SRichard Henderson if (!is_l) { 1148b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1149b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1150b2167459SRichard Henderson } 1151b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1152b2167459SRichard Henderson 1153b2167459SRichard Henderson /* Install the new nullification. */ 1154b2167459SRichard Henderson ctx->null_cond = cond; 1155b2167459SRichard Henderson } 1156b2167459SRichard Henderson 1157faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 11580c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 11590c982a28SRichard Henderson { 11606fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 11610c982a28SRichard Henderson 11620c982a28SRichard Henderson if (a->cf) { 11630c982a28SRichard Henderson nullify_over(ctx); 11640c982a28SRichard Henderson } 11650c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 11660c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1167faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1168faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 11690c982a28SRichard Henderson return nullify_end(ctx); 11700c982a28SRichard Henderson } 11710c982a28SRichard Henderson 11720588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 11730588e061SRichard Henderson bool is_tsv, bool is_tc) 11740588e061SRichard Henderson { 11756fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11760588e061SRichard Henderson 11770588e061SRichard Henderson if (a->cf) { 11780588e061SRichard Henderson nullify_over(ctx); 11790588e061SRichard Henderson } 11806fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11810588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1182faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1183faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 11840588e061SRichard Henderson return nullify_end(ctx); 11850588e061SRichard Henderson } 11860588e061SRichard Henderson 11876fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 11886fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 118963c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1190b2167459SRichard Henderson { 1191a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1192b2167459SRichard Henderson unsigned c = cf >> 1; 1193b2167459SRichard Henderson DisasCond cond; 1194b2167459SRichard Henderson 1195aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1196aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1197aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1198b2167459SRichard Henderson 1199b2167459SRichard Henderson if (is_b) { 1200b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 12016fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1202a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1203a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1204a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 12056fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 12066fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1207b2167459SRichard Henderson } else { 1208bdcccc17SRichard Henderson /* 1209bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1210bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1211bdcccc17SRichard Henderson */ 12126fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1213a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 12146fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 12156fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1216b2167459SRichard Henderson } 1217b2167459SRichard Henderson 1218b2167459SRichard Henderson /* Compute signed overflow if required. */ 1219f764718dSRichard Henderson sv = NULL; 1220b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1221b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1222b2167459SRichard Henderson if (is_tsv) { 1223bd1ad92cSSven Schnelle if (!d) { 1224bd1ad92cSSven Schnelle tcg_gen_ext32s_i64(sv, sv); 1225bd1ad92cSSven Schnelle } 1226ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1227b2167459SRichard Henderson } 1228b2167459SRichard Henderson } 1229b2167459SRichard Henderson 1230b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1231b2167459SRichard Henderson if (!is_b) { 12324fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1233b2167459SRichard Henderson } else { 1234a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1235b2167459SRichard Henderson } 1236b2167459SRichard Henderson 1237b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1238b2167459SRichard Henderson if (is_tc) { 1239aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 12406fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1241ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1242b2167459SRichard Henderson } 1243b2167459SRichard Henderson 1244b2167459SRichard Henderson /* Write back the result. */ 1245b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1246b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1247b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1248b2167459SRichard Henderson 1249b2167459SRichard Henderson /* Install the new nullification. */ 1250b2167459SRichard Henderson ctx->null_cond = cond; 1251b2167459SRichard Henderson } 1252b2167459SRichard Henderson 125363c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12540c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 12550c982a28SRichard Henderson { 12566fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12570c982a28SRichard Henderson 12580c982a28SRichard Henderson if (a->cf) { 12590c982a28SRichard Henderson nullify_over(ctx); 12600c982a28SRichard Henderson } 12610c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12620c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 126363c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 12640c982a28SRichard Henderson return nullify_end(ctx); 12650c982a28SRichard Henderson } 12660c982a28SRichard Henderson 12670588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 12680588e061SRichard Henderson { 12696fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 12700588e061SRichard Henderson 12710588e061SRichard Henderson if (a->cf) { 12720588e061SRichard Henderson nullify_over(ctx); 12730588e061SRichard Henderson } 12746fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 12750588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 127663c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 127763c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 12780588e061SRichard Henderson return nullify_end(ctx); 12790588e061SRichard Henderson } 12800588e061SRichard Henderson 12816fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12826fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1283b2167459SRichard Henderson { 12846fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1285b2167459SRichard Henderson DisasCond cond; 1286b2167459SRichard Henderson 1287aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 12886fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1289b2167459SRichard Henderson 1290b2167459SRichard Henderson /* Compute signed overflow if required. */ 1291f764718dSRichard Henderson sv = NULL; 1292b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1293b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1294b2167459SRichard Henderson } 1295b2167459SRichard Henderson 1296b2167459SRichard Henderson /* Form the condition for the compare. */ 12974fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1298b2167459SRichard Henderson 1299b2167459SRichard Henderson /* Clear. */ 13006fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1301b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1302b2167459SRichard Henderson 1303b2167459SRichard Henderson /* Install the new nullification. */ 1304b2167459SRichard Henderson ctx->null_cond = cond; 1305b2167459SRichard Henderson } 1306b2167459SRichard Henderson 13076fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 13086fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 13096fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1310b2167459SRichard Henderson { 13116fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1312b2167459SRichard Henderson 1313b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1314b2167459SRichard Henderson fn(dest, in1, in2); 1315b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1316b2167459SRichard Henderson 1317b2167459SRichard Henderson /* Install the new nullification. */ 1318b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1319b2167459SRichard Henderson } 1320b2167459SRichard Henderson 1321fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 13226fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 13230c982a28SRichard Henderson { 13246fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 13250c982a28SRichard Henderson 13260c982a28SRichard Henderson if (a->cf) { 13270c982a28SRichard Henderson nullify_over(ctx); 13280c982a28SRichard Henderson } 13290c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 13300c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1331fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 13320c982a28SRichard Henderson return nullify_end(ctx); 13330c982a28SRichard Henderson } 13340c982a28SRichard Henderson 133546bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 133646bb3d46SRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 133746bb3d46SRichard Henderson bool is_tc, bool is_add) 1338b2167459SRichard Henderson { 133946bb3d46SRichard Henderson TCGv_i64 dest = tcg_temp_new_i64(); 134046bb3d46SRichard Henderson uint64_t test_cb = 0; 1341b2167459SRichard Henderson DisasCond cond; 1342b2167459SRichard Henderson 134346bb3d46SRichard Henderson /* Select which carry-out bits to test. */ 134446bb3d46SRichard Henderson switch (cf >> 1) { 134546bb3d46SRichard Henderson case 4: /* NDC / SDC -- 4-bit carries */ 134646bb3d46SRichard Henderson test_cb = dup_const(MO_8, 0x88); 134746bb3d46SRichard Henderson break; 134846bb3d46SRichard Henderson case 5: /* NWC / SWC -- 32-bit carries */ 134946bb3d46SRichard Henderson if (d) { 135046bb3d46SRichard Henderson test_cb = dup_const(MO_32, INT32_MIN); 1351b2167459SRichard Henderson } else { 135246bb3d46SRichard Henderson cf &= 1; /* undefined -- map to never/always */ 135346bb3d46SRichard Henderson } 135446bb3d46SRichard Henderson break; 135546bb3d46SRichard Henderson case 6: /* NBC / SBC -- 8-bit carries */ 135646bb3d46SRichard Henderson test_cb = dup_const(MO_8, INT8_MIN); 135746bb3d46SRichard Henderson break; 135846bb3d46SRichard Henderson case 7: /* NHC / SHC -- 16-bit carries */ 135946bb3d46SRichard Henderson test_cb = dup_const(MO_16, INT16_MIN); 136046bb3d46SRichard Henderson break; 136146bb3d46SRichard Henderson } 136246bb3d46SRichard Henderson if (!d) { 136346bb3d46SRichard Henderson test_cb = (uint32_t)test_cb; 136446bb3d46SRichard Henderson } 1365b2167459SRichard Henderson 136646bb3d46SRichard Henderson if (!test_cb) { 136746bb3d46SRichard Henderson /* No need to compute carries if we don't need to test them. */ 136846bb3d46SRichard Henderson if (is_add) { 136946bb3d46SRichard Henderson tcg_gen_add_i64(dest, in1, in2); 137046bb3d46SRichard Henderson } else { 137146bb3d46SRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 137246bb3d46SRichard Henderson } 137346bb3d46SRichard Henderson cond = do_unit_zero_cond(cf, d, dest); 137446bb3d46SRichard Henderson } else { 137546bb3d46SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 137646bb3d46SRichard Henderson 137746bb3d46SRichard Henderson if (d) { 137846bb3d46SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 137946bb3d46SRichard Henderson if (is_add) { 138046bb3d46SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 138146bb3d46SRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 138246bb3d46SRichard Henderson } else { 138346bb3d46SRichard Henderson /* See do_sub, !is_b. */ 138446bb3d46SRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 138546bb3d46SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 138646bb3d46SRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 138746bb3d46SRichard Henderson } 138846bb3d46SRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 138946bb3d46SRichard Henderson tcg_gen_extract2_i64(cb, cb, cb_msb, 1); 139046bb3d46SRichard Henderson } else { 139146bb3d46SRichard Henderson if (is_add) { 139246bb3d46SRichard Henderson tcg_gen_add_i64(dest, in1, in2); 139346bb3d46SRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 139446bb3d46SRichard Henderson } else { 139546bb3d46SRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 139646bb3d46SRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 139746bb3d46SRichard Henderson } 139846bb3d46SRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 139946bb3d46SRichard Henderson tcg_gen_shri_i64(cb, cb, 1); 140046bb3d46SRichard Henderson } 140146bb3d46SRichard Henderson 14023289ea0eSRichard Henderson cond = cond_make_ti(cf & 1 ? TCG_COND_TSTEQ : TCG_COND_TSTNE, 14033289ea0eSRichard Henderson cb, test_cb); 140446bb3d46SRichard Henderson } 1405b2167459SRichard Henderson 1406b2167459SRichard Henderson if (is_tc) { 1407aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 14086fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1409ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1410b2167459SRichard Henderson } 1411b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1412b2167459SRichard Henderson 1413b2167459SRichard Henderson ctx->null_cond = cond; 1414b2167459SRichard Henderson } 1415b2167459SRichard Henderson 141686f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 14178d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 14188d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 14198d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 14208d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 14216fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 142286f8d05fSRichard Henderson { 142386f8d05fSRichard Henderson TCGv_ptr ptr; 14246fd0c7bcSRichard Henderson TCGv_i64 tmp; 142586f8d05fSRichard Henderson TCGv_i64 spc; 142686f8d05fSRichard Henderson 142786f8d05fSRichard Henderson if (sp != 0) { 14288d6ae7fbSRichard Henderson if (sp < 0) { 14298d6ae7fbSRichard Henderson sp = ~sp; 14308d6ae7fbSRichard Henderson } 14316fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 14328d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 14338d6ae7fbSRichard Henderson return spc; 143486f8d05fSRichard Henderson } 1435494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1436494737b7SRichard Henderson return cpu_srH; 1437494737b7SRichard Henderson } 143886f8d05fSRichard Henderson 143986f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1440aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 14416fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 144286f8d05fSRichard Henderson 1443698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 14446fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 14456fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 14466fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 144786f8d05fSRichard Henderson 1448ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 144986f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 145086f8d05fSRichard Henderson 145186f8d05fSRichard Henderson return spc; 145286f8d05fSRichard Henderson } 145386f8d05fSRichard Henderson #endif 145486f8d05fSRichard Henderson 14556fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1456c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 145786f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 145886f8d05fSRichard Henderson { 14596fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 14606fd0c7bcSRichard Henderson TCGv_i64 ofs; 14616fd0c7bcSRichard Henderson TCGv_i64 addr; 146286f8d05fSRichard Henderson 1463f5b5c857SRichard Henderson set_insn_breg(ctx, rb); 1464f5b5c857SRichard Henderson 146586f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 146686f8d05fSRichard Henderson if (rx) { 1467aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 14686fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 14696fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 147086f8d05fSRichard Henderson } else if (disp || modify) { 1471aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 14726fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 147386f8d05fSRichard Henderson } else { 147486f8d05fSRichard Henderson ofs = base; 147586f8d05fSRichard Henderson } 147686f8d05fSRichard Henderson 147786f8d05fSRichard Henderson *pofs = ofs; 14786fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 14797d50b696SSven Schnelle tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, 14807d50b696SSven Schnelle gva_offset_mask(ctx->tb_flags)); 1481698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 148286f8d05fSRichard Henderson if (!is_phys) { 1483d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 148486f8d05fSRichard Henderson } 148586f8d05fSRichard Henderson #endif 148686f8d05fSRichard Henderson } 148786f8d05fSRichard Henderson 148896d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 148996d6407fSRichard Henderson * < 0 for pre-modify, 149096d6407fSRichard Henderson * > 0 for post-modify, 149196d6407fSRichard Henderson * = 0 for no base register update. 149296d6407fSRichard Henderson */ 149396d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1494c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 149514776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 149696d6407fSRichard Henderson { 14976fd0c7bcSRichard Henderson TCGv_i64 ofs; 14986fd0c7bcSRichard Henderson TCGv_i64 addr; 149996d6407fSRichard Henderson 150096d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 150196d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 150296d6407fSRichard Henderson 150386f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 150417fe594cSRichard Henderson MMU_DISABLED(ctx)); 1505c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 150686f8d05fSRichard Henderson if (modify) { 150786f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 150896d6407fSRichard Henderson } 150996d6407fSRichard Henderson } 151096d6407fSRichard Henderson 151196d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1512c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 151314776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 151496d6407fSRichard Henderson { 15156fd0c7bcSRichard Henderson TCGv_i64 ofs; 15166fd0c7bcSRichard Henderson TCGv_i64 addr; 151796d6407fSRichard Henderson 151896d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 151996d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 152096d6407fSRichard Henderson 152186f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 152217fe594cSRichard Henderson MMU_DISABLED(ctx)); 1523217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 152486f8d05fSRichard Henderson if (modify) { 152586f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 152696d6407fSRichard Henderson } 152796d6407fSRichard Henderson } 152896d6407fSRichard Henderson 152996d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1530c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 153114776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 153296d6407fSRichard Henderson { 15336fd0c7bcSRichard Henderson TCGv_i64 ofs; 15346fd0c7bcSRichard Henderson TCGv_i64 addr; 153596d6407fSRichard Henderson 153696d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 153796d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 153896d6407fSRichard Henderson 153986f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 154017fe594cSRichard Henderson MMU_DISABLED(ctx)); 1541217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 154286f8d05fSRichard Henderson if (modify) { 154386f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 154496d6407fSRichard Henderson } 154596d6407fSRichard Henderson } 154696d6407fSRichard Henderson 154796d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1548c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 154914776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 155096d6407fSRichard Henderson { 15516fd0c7bcSRichard Henderson TCGv_i64 ofs; 15526fd0c7bcSRichard Henderson TCGv_i64 addr; 155396d6407fSRichard Henderson 155496d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 155596d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 155696d6407fSRichard Henderson 155786f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 155817fe594cSRichard Henderson MMU_DISABLED(ctx)); 1559217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 156086f8d05fSRichard Henderson if (modify) { 156186f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 156296d6407fSRichard Henderson } 156396d6407fSRichard Henderson } 156496d6407fSRichard Henderson 15651cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1566c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 156714776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 156896d6407fSRichard Henderson { 15696fd0c7bcSRichard Henderson TCGv_i64 dest; 157096d6407fSRichard Henderson 157196d6407fSRichard Henderson nullify_over(ctx); 157296d6407fSRichard Henderson 157396d6407fSRichard Henderson if (modify == 0) { 157496d6407fSRichard Henderson /* No base register update. */ 157596d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 157696d6407fSRichard Henderson } else { 157796d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1578aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 157996d6407fSRichard Henderson } 15806fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 158196d6407fSRichard Henderson save_gpr(ctx, rt, dest); 158296d6407fSRichard Henderson 15831cd012a5SRichard Henderson return nullify_end(ctx); 158496d6407fSRichard Henderson } 158596d6407fSRichard Henderson 1586740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1587c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 158886f8d05fSRichard Henderson unsigned sp, int modify) 158996d6407fSRichard Henderson { 159096d6407fSRichard Henderson TCGv_i32 tmp; 159196d6407fSRichard Henderson 159296d6407fSRichard Henderson nullify_over(ctx); 159396d6407fSRichard Henderson 159496d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 159586f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 159696d6407fSRichard Henderson save_frw_i32(rt, tmp); 159796d6407fSRichard Henderson 159896d6407fSRichard Henderson if (rt == 0) { 1599ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 160096d6407fSRichard Henderson } 160196d6407fSRichard Henderson 1602740038d7SRichard Henderson return nullify_end(ctx); 160396d6407fSRichard Henderson } 160496d6407fSRichard Henderson 1605740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1606740038d7SRichard Henderson { 1607740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1608740038d7SRichard Henderson a->disp, a->sp, a->m); 1609740038d7SRichard Henderson } 1610740038d7SRichard Henderson 1611740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1612c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 161386f8d05fSRichard Henderson unsigned sp, int modify) 161496d6407fSRichard Henderson { 161596d6407fSRichard Henderson TCGv_i64 tmp; 161696d6407fSRichard Henderson 161796d6407fSRichard Henderson nullify_over(ctx); 161896d6407fSRichard Henderson 161996d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1620fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 162196d6407fSRichard Henderson save_frd(rt, tmp); 162296d6407fSRichard Henderson 162396d6407fSRichard Henderson if (rt == 0) { 1624ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 162596d6407fSRichard Henderson } 162696d6407fSRichard Henderson 1627740038d7SRichard Henderson return nullify_end(ctx); 1628740038d7SRichard Henderson } 1629740038d7SRichard Henderson 1630740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1631740038d7SRichard Henderson { 1632740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1633740038d7SRichard Henderson a->disp, a->sp, a->m); 163496d6407fSRichard Henderson } 163596d6407fSRichard Henderson 16361cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1637c53e401eSRichard Henderson int64_t disp, unsigned sp, 163814776ab5STony Nguyen int modify, MemOp mop) 163996d6407fSRichard Henderson { 164096d6407fSRichard Henderson nullify_over(ctx); 16416fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 16421cd012a5SRichard Henderson return nullify_end(ctx); 164396d6407fSRichard Henderson } 164496d6407fSRichard Henderson 1645740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1646c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 164786f8d05fSRichard Henderson unsigned sp, int modify) 164896d6407fSRichard Henderson { 164996d6407fSRichard Henderson TCGv_i32 tmp; 165096d6407fSRichard Henderson 165196d6407fSRichard Henderson nullify_over(ctx); 165296d6407fSRichard Henderson 165396d6407fSRichard Henderson tmp = load_frw_i32(rt); 165486f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 165596d6407fSRichard Henderson 1656740038d7SRichard Henderson return nullify_end(ctx); 165796d6407fSRichard Henderson } 165896d6407fSRichard Henderson 1659740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1660740038d7SRichard Henderson { 1661740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1662740038d7SRichard Henderson a->disp, a->sp, a->m); 1663740038d7SRichard Henderson } 1664740038d7SRichard Henderson 1665740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1666c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 166786f8d05fSRichard Henderson unsigned sp, int modify) 166896d6407fSRichard Henderson { 166996d6407fSRichard Henderson TCGv_i64 tmp; 167096d6407fSRichard Henderson 167196d6407fSRichard Henderson nullify_over(ctx); 167296d6407fSRichard Henderson 167396d6407fSRichard Henderson tmp = load_frd(rt); 1674fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 167596d6407fSRichard Henderson 1676740038d7SRichard Henderson return nullify_end(ctx); 1677740038d7SRichard Henderson } 1678740038d7SRichard Henderson 1679740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1680740038d7SRichard Henderson { 1681740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1682740038d7SRichard Henderson a->disp, a->sp, a->m); 168396d6407fSRichard Henderson } 168496d6407fSRichard Henderson 16851ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1686ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1687ebe9383cSRichard Henderson { 1688ebe9383cSRichard Henderson TCGv_i32 tmp; 1689ebe9383cSRichard Henderson 1690ebe9383cSRichard Henderson nullify_over(ctx); 1691ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1692ebe9383cSRichard Henderson 1693ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1694ebe9383cSRichard Henderson 1695ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 16961ca74648SRichard Henderson return nullify_end(ctx); 1697ebe9383cSRichard Henderson } 1698ebe9383cSRichard Henderson 16991ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1700ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1701ebe9383cSRichard Henderson { 1702ebe9383cSRichard Henderson TCGv_i32 dst; 1703ebe9383cSRichard Henderson TCGv_i64 src; 1704ebe9383cSRichard Henderson 1705ebe9383cSRichard Henderson nullify_over(ctx); 1706ebe9383cSRichard Henderson src = load_frd(ra); 1707ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1708ebe9383cSRichard Henderson 1709ad75a51eSRichard Henderson func(dst, tcg_env, src); 1710ebe9383cSRichard Henderson 1711ebe9383cSRichard Henderson save_frw_i32(rt, dst); 17121ca74648SRichard Henderson return nullify_end(ctx); 1713ebe9383cSRichard Henderson } 1714ebe9383cSRichard Henderson 17151ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1716ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1717ebe9383cSRichard Henderson { 1718ebe9383cSRichard Henderson TCGv_i64 tmp; 1719ebe9383cSRichard Henderson 1720ebe9383cSRichard Henderson nullify_over(ctx); 1721ebe9383cSRichard Henderson tmp = load_frd0(ra); 1722ebe9383cSRichard Henderson 1723ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1724ebe9383cSRichard Henderson 1725ebe9383cSRichard Henderson save_frd(rt, tmp); 17261ca74648SRichard Henderson return nullify_end(ctx); 1727ebe9383cSRichard Henderson } 1728ebe9383cSRichard Henderson 17291ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1730ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1731ebe9383cSRichard Henderson { 1732ebe9383cSRichard Henderson TCGv_i32 src; 1733ebe9383cSRichard Henderson TCGv_i64 dst; 1734ebe9383cSRichard Henderson 1735ebe9383cSRichard Henderson nullify_over(ctx); 1736ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1737ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1738ebe9383cSRichard Henderson 1739ad75a51eSRichard Henderson func(dst, tcg_env, src); 1740ebe9383cSRichard Henderson 1741ebe9383cSRichard Henderson save_frd(rt, dst); 17421ca74648SRichard Henderson return nullify_end(ctx); 1743ebe9383cSRichard Henderson } 1744ebe9383cSRichard Henderson 17451ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1746ebe9383cSRichard Henderson unsigned ra, unsigned rb, 174731234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1748ebe9383cSRichard Henderson { 1749ebe9383cSRichard Henderson TCGv_i32 a, b; 1750ebe9383cSRichard Henderson 1751ebe9383cSRichard Henderson nullify_over(ctx); 1752ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1753ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1754ebe9383cSRichard Henderson 1755ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1756ebe9383cSRichard Henderson 1757ebe9383cSRichard Henderson save_frw_i32(rt, a); 17581ca74648SRichard Henderson return nullify_end(ctx); 1759ebe9383cSRichard Henderson } 1760ebe9383cSRichard Henderson 17611ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1762ebe9383cSRichard Henderson unsigned ra, unsigned rb, 176331234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1764ebe9383cSRichard Henderson { 1765ebe9383cSRichard Henderson TCGv_i64 a, b; 1766ebe9383cSRichard Henderson 1767ebe9383cSRichard Henderson nullify_over(ctx); 1768ebe9383cSRichard Henderson a = load_frd0(ra); 1769ebe9383cSRichard Henderson b = load_frd0(rb); 1770ebe9383cSRichard Henderson 1771ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1772ebe9383cSRichard Henderson 1773ebe9383cSRichard Henderson save_frd(rt, a); 17741ca74648SRichard Henderson return nullify_end(ctx); 1775ebe9383cSRichard Henderson } 1776ebe9383cSRichard Henderson 177798cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 177898cd9ca7SRichard Henderson have already had nullification handled. */ 17792644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp, 178098cd9ca7SRichard Henderson unsigned link, bool is_n) 178198cd9ca7SRichard Henderson { 1782bc921866SRichard Henderson ctx->iaq_j = iaqe_branchi(ctx, disp); 17832644f80bSRichard Henderson 178498cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 178543541db0SRichard Henderson install_link(ctx, link, false); 178698cd9ca7SRichard Henderson if (is_n) { 1787d08ad0e0SRichard Henderson if (use_nullify_skip(ctx)) { 1788d08ad0e0SRichard Henderson nullify_set(ctx, 0); 1789bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL); 1790d08ad0e0SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 1791d08ad0e0SRichard Henderson return true; 1792d08ad0e0SRichard Henderson } 179398cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 179498cd9ca7SRichard Henderson } 1795bc921866SRichard Henderson ctx->iaq_n = &ctx->iaq_j; 179698cd9ca7SRichard Henderson } else { 179798cd9ca7SRichard Henderson nullify_over(ctx); 179898cd9ca7SRichard Henderson 179943541db0SRichard Henderson install_link(ctx, link, false); 180098cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 180198cd9ca7SRichard Henderson nullify_set(ctx, 0); 1802bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL); 180398cd9ca7SRichard Henderson } else { 180498cd9ca7SRichard Henderson nullify_set(ctx, is_n); 1805bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_b, &ctx->iaq_j); 180698cd9ca7SRichard Henderson } 180731234768SRichard Henderson nullify_end(ctx); 180898cd9ca7SRichard Henderson 180998cd9ca7SRichard Henderson nullify_set(ctx, 0); 1810bc921866SRichard Henderson gen_goto_tb(ctx, 1, &ctx->iaq_b, NULL); 181131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 181298cd9ca7SRichard Henderson } 181301afb7beSRichard Henderson return true; 181498cd9ca7SRichard Henderson } 181598cd9ca7SRichard Henderson 181698cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 181798cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1818c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 181998cd9ca7SRichard Henderson DisasCond *cond) 182098cd9ca7SRichard Henderson { 1821bc921866SRichard Henderson DisasIAQE next; 182298cd9ca7SRichard Henderson TCGLabel *taken = NULL; 182398cd9ca7SRichard Henderson TCGCond c = cond->c; 182498cd9ca7SRichard Henderson bool n; 182598cd9ca7SRichard Henderson 182698cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 182798cd9ca7SRichard Henderson 182898cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 182998cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 18302644f80bSRichard Henderson return do_dbranch(ctx, disp, 0, is_n && disp >= 0); 183198cd9ca7SRichard Henderson } 183298cd9ca7SRichard Henderson 183398cd9ca7SRichard Henderson taken = gen_new_label(); 18346fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 183598cd9ca7SRichard Henderson 183698cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 183798cd9ca7SRichard Henderson n = is_n && disp < 0; 183898cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 183998cd9ca7SRichard Henderson nullify_set(ctx, 0); 1840bc921866SRichard Henderson next = iaqe_incr(&ctx->iaq_b, 4); 1841bc921866SRichard Henderson gen_goto_tb(ctx, 0, &next, NULL); 184298cd9ca7SRichard Henderson } else { 184398cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 184498cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 184598cd9ca7SRichard Henderson ctx->null_lab = NULL; 184698cd9ca7SRichard Henderson } 184798cd9ca7SRichard Henderson nullify_set(ctx, n); 1848bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_b, NULL); 184998cd9ca7SRichard Henderson } 185098cd9ca7SRichard Henderson 185198cd9ca7SRichard Henderson gen_set_label(taken); 185298cd9ca7SRichard Henderson 185398cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 185498cd9ca7SRichard Henderson n = is_n && disp >= 0; 1855bc921866SRichard Henderson 1856bc921866SRichard Henderson next = iaqe_branchi(ctx, disp); 185798cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 185898cd9ca7SRichard Henderson nullify_set(ctx, 0); 1859bc921866SRichard Henderson gen_goto_tb(ctx, 1, &next, NULL); 186098cd9ca7SRichard Henderson } else { 186198cd9ca7SRichard Henderson nullify_set(ctx, n); 1862bc921866SRichard Henderson gen_goto_tb(ctx, 1, &ctx->iaq_b, &next); 186398cd9ca7SRichard Henderson } 186498cd9ca7SRichard Henderson 186598cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 186698cd9ca7SRichard Henderson if (ctx->null_lab) { 186798cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 186898cd9ca7SRichard Henderson ctx->null_lab = NULL; 186931234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 187098cd9ca7SRichard Henderson } else { 187131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 187298cd9ca7SRichard Henderson } 187301afb7beSRichard Henderson return true; 187498cd9ca7SRichard Henderson } 187598cd9ca7SRichard Henderson 1876bc921866SRichard Henderson /* 1877bc921866SRichard Henderson * Emit an unconditional branch to an indirect target, in ctx->iaq_j. 1878bc921866SRichard Henderson * This handles nullification of the branch itself. 1879bc921866SRichard Henderson */ 1880bc921866SRichard Henderson static bool do_ibranch(DisasContext *ctx, unsigned link, 1881bc921866SRichard Henderson bool with_sr0, bool is_n) 188298cd9ca7SRichard Henderson { 1883d582c1faSRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 1884019f4159SRichard Henderson install_link(ctx, link, with_sr0); 188598cd9ca7SRichard Henderson if (is_n) { 1886c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1887bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_j, NULL); 1888c301f34eSRichard Henderson nullify_set(ctx, 0); 188931234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 189001afb7beSRichard Henderson return true; 1891c301f34eSRichard Henderson } 189298cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 189398cd9ca7SRichard Henderson } 1894bc921866SRichard Henderson ctx->iaq_n = &ctx->iaq_j; 1895d582c1faSRichard Henderson return true; 1896d582c1faSRichard Henderson } 189798cd9ca7SRichard Henderson 1898d582c1faSRichard Henderson nullify_over(ctx); 1899d582c1faSRichard Henderson 1900019f4159SRichard Henderson install_link(ctx, link, with_sr0); 1901d582c1faSRichard Henderson if (is_n && use_nullify_skip(ctx)) { 1902bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_j, NULL); 1903d582c1faSRichard Henderson nullify_set(ctx, 0); 1904d582c1faSRichard Henderson } else { 1905bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j); 1906d582c1faSRichard Henderson nullify_set(ctx, is_n); 1907d582c1faSRichard Henderson } 1908d582c1faSRichard Henderson 19097f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 1910d582c1faSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 191101afb7beSRichard Henderson return nullify_end(ctx); 191298cd9ca7SRichard Henderson } 191398cd9ca7SRichard Henderson 1914660eefe1SRichard Henderson /* Implement 1915660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1916660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1917660eefe1SRichard Henderson * else 1918660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1919660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1920660eefe1SRichard Henderson */ 19216fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1922660eefe1SRichard Henderson { 19231874e6c2SRichard Henderson TCGv_i64 dest = tcg_temp_new_i64(); 1924660eefe1SRichard Henderson switch (ctx->privilege) { 1925660eefe1SRichard Henderson case 0: 1926660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 19271874e6c2SRichard Henderson tcg_gen_mov_i64(dest, offset); 19281874e6c2SRichard Henderson break; 1929660eefe1SRichard Henderson case 3: 1930993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 19316fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1932660eefe1SRichard Henderson break; 1933660eefe1SRichard Henderson default: 19346fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 19356fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 19360bb02029SRichard Henderson tcg_gen_umax_i64(dest, dest, offset); 1937660eefe1SRichard Henderson break; 1938660eefe1SRichard Henderson } 1939660eefe1SRichard Henderson return dest; 1940660eefe1SRichard Henderson } 1941660eefe1SRichard Henderson 1942ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 19437ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 19447ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 19457ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 19467ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 19477ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 19487ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 19497ad439dfSRichard Henderson aforementioned BE. */ 195031234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 19517ad439dfSRichard Henderson { 19520d89cb7cSRichard Henderson assert(ctx->iaq_f.disp == 0); 19530d89cb7cSRichard Henderson 19547ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 19557ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 19568b81968cSMichael Tokarev next insn within the privileged page. */ 19577ad439dfSRichard Henderson switch (ctx->null_cond.c) { 19587ad439dfSRichard Henderson case TCG_COND_NEVER: 19597ad439dfSRichard Henderson break; 19607ad439dfSRichard Henderson case TCG_COND_ALWAYS: 19616fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 19627ad439dfSRichard Henderson goto do_sigill; 19637ad439dfSRichard Henderson default: 19647ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 19657ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 19667ad439dfSRichard Henderson g_assert_not_reached(); 19677ad439dfSRichard Henderson } 19687ad439dfSRichard Henderson 19697ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 19707ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 19717ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 19727ad439dfSRichard Henderson under such conditions. */ 19730d89cb7cSRichard Henderson if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != 4) { 19747ad439dfSRichard Henderson goto do_sigill; 19757ad439dfSRichard Henderson } 19767ad439dfSRichard Henderson 19770d89cb7cSRichard Henderson switch (ctx->base.pc_first) { 19787ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 19792986721dSRichard Henderson gen_excp_1(EXCP_IMP); 198031234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 198131234768SRichard Henderson break; 19827ad439dfSRichard Henderson 19837ad439dfSRichard Henderson case 0xb0: /* LWS */ 19847ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 198531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 198631234768SRichard Henderson break; 19877ad439dfSRichard Henderson 19887ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 1989bc921866SRichard Henderson { 1990bc921866SRichard Henderson DisasIAQE next = { .base = tcg_temp_new_i64() }; 1991bc921866SRichard Henderson 1992bc921866SRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, 1993bc921866SRichard Henderson offsetof(CPUHPPAState, cr[27])); 1994bc921866SRichard Henderson tcg_gen_ori_i64(next.base, cpu_gr[31], 3); 1995bc921866SRichard Henderson install_iaq_entries(ctx, &next, NULL); 199631234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 1997bc921866SRichard Henderson } 199831234768SRichard Henderson break; 19997ad439dfSRichard Henderson 20007ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 20017ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 200231234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 200331234768SRichard Henderson break; 20047ad439dfSRichard Henderson 20057ad439dfSRichard Henderson default: 20067ad439dfSRichard Henderson do_sigill: 20072986721dSRichard Henderson gen_excp_1(EXCP_ILL); 200831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 200931234768SRichard Henderson break; 20107ad439dfSRichard Henderson } 20117ad439dfSRichard Henderson } 2012ba1d0b44SRichard Henderson #endif 20137ad439dfSRichard Henderson 2014deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 2015b2167459SRichard Henderson { 2016*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 201731234768SRichard Henderson return true; 2018b2167459SRichard Henderson } 2019b2167459SRichard Henderson 202040f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 202198a9cb79SRichard Henderson { 202231234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 202398a9cb79SRichard Henderson } 202498a9cb79SRichard Henderson 2025e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 202698a9cb79SRichard Henderson { 202798a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 202898a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 202998a9cb79SRichard Henderson 2030*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 203131234768SRichard Henderson return true; 203298a9cb79SRichard Henderson } 203398a9cb79SRichard Henderson 2034c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 203598a9cb79SRichard Henderson { 2036bc921866SRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 203798a9cb79SRichard Henderson 2038bc921866SRichard Henderson copy_iaoq_entry(ctx, dest, &ctx->iaq_f); 2039bc921866SRichard Henderson tcg_gen_andi_i64(dest, dest, -4); 2040bc921866SRichard Henderson 2041bc921866SRichard Henderson save_gpr(ctx, a->t, dest); 2042*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 204331234768SRichard Henderson return true; 204498a9cb79SRichard Henderson } 204598a9cb79SRichard Henderson 2046c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 204798a9cb79SRichard Henderson { 2048c603e14aSRichard Henderson unsigned rt = a->t; 2049c603e14aSRichard Henderson unsigned rs = a->sp; 205033423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 205198a9cb79SRichard Henderson 205233423472SRichard Henderson load_spr(ctx, t0, rs); 205333423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 205433423472SRichard Henderson 2055967662cdSRichard Henderson save_gpr(ctx, rt, t0); 205698a9cb79SRichard Henderson 2057*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 205831234768SRichard Henderson return true; 205998a9cb79SRichard Henderson } 206098a9cb79SRichard Henderson 2061c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 206298a9cb79SRichard Henderson { 2063c603e14aSRichard Henderson unsigned rt = a->t; 2064c603e14aSRichard Henderson unsigned ctl = a->r; 20656fd0c7bcSRichard Henderson TCGv_i64 tmp; 206698a9cb79SRichard Henderson 206798a9cb79SRichard Henderson switch (ctl) { 206835136a77SRichard Henderson case CR_SAR: 2069c603e14aSRichard Henderson if (a->e == 0) { 207098a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 207198a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 20726fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 207398a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 207435136a77SRichard Henderson goto done; 207598a9cb79SRichard Henderson } 207698a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 207735136a77SRichard Henderson goto done; 207835136a77SRichard Henderson case CR_IT: /* Interval Timer */ 207935136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 208035136a77SRichard Henderson nullify_over(ctx); 208198a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2082dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 208331234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 208449c29d6cSRichard Henderson } 20850c58c1bcSRichard Henderson gen_helper_read_interval_timer(tmp); 208698a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 208731234768SRichard Henderson return nullify_end(ctx); 208898a9cb79SRichard Henderson case 26: 208998a9cb79SRichard Henderson case 27: 209098a9cb79SRichard Henderson break; 209198a9cb79SRichard Henderson default: 209298a9cb79SRichard Henderson /* All other control registers are privileged. */ 209335136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 209435136a77SRichard Henderson break; 209598a9cb79SRichard Henderson } 209698a9cb79SRichard Henderson 2097aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20986fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 209935136a77SRichard Henderson save_gpr(ctx, rt, tmp); 210035136a77SRichard Henderson 210135136a77SRichard Henderson done: 2102*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 210331234768SRichard Henderson return true; 210498a9cb79SRichard Henderson } 210598a9cb79SRichard Henderson 2106c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 210733423472SRichard Henderson { 2108c603e14aSRichard Henderson unsigned rr = a->r; 2109c603e14aSRichard Henderson unsigned rs = a->sp; 2110967662cdSRichard Henderson TCGv_i64 tmp; 211133423472SRichard Henderson 211233423472SRichard Henderson if (rs >= 5) { 211333423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 211433423472SRichard Henderson } 211533423472SRichard Henderson nullify_over(ctx); 211633423472SRichard Henderson 2117967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2118967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 211933423472SRichard Henderson 212033423472SRichard Henderson if (rs >= 4) { 2121967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2122494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 212333423472SRichard Henderson } else { 2124967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 212533423472SRichard Henderson } 212633423472SRichard Henderson 212731234768SRichard Henderson return nullify_end(ctx); 212833423472SRichard Henderson } 212933423472SRichard Henderson 2130c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 213198a9cb79SRichard Henderson { 2132c603e14aSRichard Henderson unsigned ctl = a->t; 21336fd0c7bcSRichard Henderson TCGv_i64 reg; 21346fd0c7bcSRichard Henderson TCGv_i64 tmp; 213598a9cb79SRichard Henderson 213635136a77SRichard Henderson if (ctl == CR_SAR) { 21374845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2138aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21396fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 214098a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 214198a9cb79SRichard Henderson 2142*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 214331234768SRichard Henderson return true; 214498a9cb79SRichard Henderson } 214598a9cb79SRichard Henderson 214635136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 214735136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 214835136a77SRichard Henderson 2149c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 215035136a77SRichard Henderson nullify_over(ctx); 21514c34bab0SHelge Deller 21524c34bab0SHelge Deller if (ctx->is_pa20) { 21534845f015SSven Schnelle reg = load_gpr(ctx, a->r); 21544c34bab0SHelge Deller } else { 21554c34bab0SHelge Deller reg = tcg_temp_new_i64(); 21564c34bab0SHelge Deller tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 21574c34bab0SHelge Deller } 21584845f015SSven Schnelle 215935136a77SRichard Henderson switch (ctl) { 216035136a77SRichard Henderson case CR_IT: 2161104281c1SRichard Henderson if (translator_io_start(&ctx->base)) { 2162104281c1SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2163104281c1SRichard Henderson } 2164ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 216535136a77SRichard Henderson break; 21664f5f2548SRichard Henderson case CR_EIRR: 21676ebebea7SRichard Henderson /* Helper modifies interrupt lines and is therefore IO. */ 21686ebebea7SRichard Henderson translator_io_start(&ctx->base); 2169ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 21706ebebea7SRichard Henderson /* Exit to re-evaluate interrupts in the main loop. */ 217131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 21724f5f2548SRichard Henderson break; 21734f5f2548SRichard Henderson 217435136a77SRichard Henderson case CR_IIASQ: 217535136a77SRichard Henderson case CR_IIAOQ: 217635136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 217735136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2178aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21796fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 218035136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 21816fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 21826fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 218335136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 218435136a77SRichard Henderson break; 218535136a77SRichard Henderson 2186d5de20bdSSven Schnelle case CR_PID1: 2187d5de20bdSSven Schnelle case CR_PID2: 2188d5de20bdSSven Schnelle case CR_PID3: 2189d5de20bdSSven Schnelle case CR_PID4: 21906fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2191d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2192ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2193d5de20bdSSven Schnelle #endif 2194d5de20bdSSven Schnelle break; 2195d5de20bdSSven Schnelle 21966ebebea7SRichard Henderson case CR_EIEM: 21976ebebea7SRichard Henderson /* Exit to re-evaluate interrupts in the main loop. */ 21986ebebea7SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 21996ebebea7SRichard Henderson /* FALLTHRU */ 220035136a77SRichard Henderson default: 22016fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 220235136a77SRichard Henderson break; 220335136a77SRichard Henderson } 220431234768SRichard Henderson return nullify_end(ctx); 22054f5f2548SRichard Henderson #endif 220635136a77SRichard Henderson } 220735136a77SRichard Henderson 2208c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 220998a9cb79SRichard Henderson { 2210aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 221198a9cb79SRichard Henderson 22126fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 22136fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 221498a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 221598a9cb79SRichard Henderson 2216*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 221731234768SRichard Henderson return true; 221898a9cb79SRichard Henderson } 221998a9cb79SRichard Henderson 2220e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 222198a9cb79SRichard Henderson { 22226fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 222398a9cb79SRichard Henderson 22242330504cSHelge Deller #ifdef CONFIG_USER_ONLY 22252330504cSHelge Deller /* We don't implement space registers in user mode. */ 22266fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 22272330504cSHelge Deller #else 2228967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2229967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 22302330504cSHelge Deller #endif 2231e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 223298a9cb79SRichard Henderson 2233*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 223431234768SRichard Henderson return true; 223598a9cb79SRichard Henderson } 223698a9cb79SRichard Henderson 2237e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2238e36f27efSRichard Henderson { 22397b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY 2240e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22417b2d70a1SHelge Deller #else 22426fd0c7bcSRichard Henderson TCGv_i64 tmp; 2243e1b5a5edSRichard Henderson 22447b2d70a1SHelge Deller /* HP-UX 11i and HP ODE use rsm for read-access to PSW */ 22457b2d70a1SHelge Deller if (a->i) { 22467b2d70a1SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22477b2d70a1SHelge Deller } 22487b2d70a1SHelge Deller 2249e1b5a5edSRichard Henderson nullify_over(ctx); 2250e1b5a5edSRichard Henderson 2251aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22526fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 22536fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2254ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2255e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2256e1b5a5edSRichard Henderson 2257e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 225831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 225931234768SRichard Henderson return nullify_end(ctx); 2260e36f27efSRichard Henderson #endif 2261e1b5a5edSRichard Henderson } 2262e1b5a5edSRichard Henderson 2263e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2264e1b5a5edSRichard Henderson { 2265e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2266e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 22676fd0c7bcSRichard Henderson TCGv_i64 tmp; 2268e1b5a5edSRichard Henderson 2269e1b5a5edSRichard Henderson nullify_over(ctx); 2270e1b5a5edSRichard Henderson 2271aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22726fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 22736fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2274ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2275e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2276e1b5a5edSRichard Henderson 2277e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 227831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 227931234768SRichard Henderson return nullify_end(ctx); 2280e36f27efSRichard Henderson #endif 2281e1b5a5edSRichard Henderson } 2282e1b5a5edSRichard Henderson 2283c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2284e1b5a5edSRichard Henderson { 2285e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2286c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 22876fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2288e1b5a5edSRichard Henderson nullify_over(ctx); 2289e1b5a5edSRichard Henderson 2290c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2291aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2292ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2293e1b5a5edSRichard Henderson 2294e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 229531234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 229631234768SRichard Henderson return nullify_end(ctx); 2297c603e14aSRichard Henderson #endif 2298e1b5a5edSRichard Henderson } 2299f49b3537SRichard Henderson 2300e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2301f49b3537SRichard Henderson { 2302f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2303e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2304f49b3537SRichard Henderson nullify_over(ctx); 2305f49b3537SRichard Henderson 2306e36f27efSRichard Henderson if (rfi_r) { 2307ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2308f49b3537SRichard Henderson } else { 2309ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2310f49b3537SRichard Henderson } 231131234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 231207ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 231331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2314f49b3537SRichard Henderson 231531234768SRichard Henderson return nullify_end(ctx); 2316e36f27efSRichard Henderson #endif 2317f49b3537SRichard Henderson } 23186210db05SHelge Deller 2319e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2320e36f27efSRichard Henderson { 2321e36f27efSRichard Henderson return do_rfi(ctx, false); 2322e36f27efSRichard Henderson } 2323e36f27efSRichard Henderson 2324e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2325e36f27efSRichard Henderson { 2326e36f27efSRichard Henderson return do_rfi(ctx, true); 2327e36f27efSRichard Henderson } 2328e36f27efSRichard Henderson 232996927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 23306210db05SHelge Deller { 23316210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 233296927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 23336210db05SHelge Deller nullify_over(ctx); 2334ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 233531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 233631234768SRichard Henderson return nullify_end(ctx); 233796927adbSRichard Henderson #endif 23386210db05SHelge Deller } 233996927adbSRichard Henderson 234096927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 234196927adbSRichard Henderson { 234296927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 234396927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 234496927adbSRichard Henderson nullify_over(ctx); 2345ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 234696927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 234796927adbSRichard Henderson return nullify_end(ctx); 234896927adbSRichard Henderson #endif 234996927adbSRichard Henderson } 2350e1b5a5edSRichard Henderson 2351558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx) 23524a4554c6SHelge Deller { 23534a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 23544a4554c6SHelge Deller nullify_over(ctx); 2355558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0])); 2356558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1])); 2357558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2])); 2358558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3])); 2359558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4])); 2360558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5])); 2361558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6])); 23624a4554c6SHelge Deller return nullify_end(ctx); 2363558c09beSRichard Henderson } 2364558c09beSRichard Henderson 23653bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx) 23663bdf2081SHelge Deller { 23673bdf2081SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 23683bdf2081SHelge Deller nullify_over(ctx); 23693bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0])); 23703bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1])); 23713bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2])); 23723bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3])); 23733bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4])); 23743bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5])); 23753bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6])); 23763bdf2081SHelge Deller return nullify_end(ctx); 23773bdf2081SHelge Deller } 23783bdf2081SHelge Deller 2379558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 2380558c09beSRichard Henderson { 2381558c09beSRichard Henderson return do_getshadowregs(ctx); 23824a4554c6SHelge Deller } 23834a4554c6SHelge Deller 2384deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 238598a9cb79SRichard Henderson { 2386deee69a1SRichard Henderson if (a->m) { 23876fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 23886fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 23896fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 239098a9cb79SRichard Henderson 239198a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 23926fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2393deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2394deee69a1SRichard Henderson } 2395*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 239631234768SRichard Henderson return true; 239798a9cb79SRichard Henderson } 239898a9cb79SRichard Henderson 2399ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a) 2400ad1fdacdSSven Schnelle { 2401ad1fdacdSSven Schnelle /* End TB for flush instruction cache, so we pick up new insns. */ 2402ad1fdacdSSven Schnelle ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2403ad1fdacdSSven Schnelle return trans_nop_addrx(ctx, a); 2404ad1fdacdSSven Schnelle } 2405ad1fdacdSSven Schnelle 2406deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 240798a9cb79SRichard Henderson { 24086fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2409eed14219SRichard Henderson TCGv_i32 level, want; 24106fd0c7bcSRichard Henderson TCGv_i64 addr; 241198a9cb79SRichard Henderson 241298a9cb79SRichard Henderson nullify_over(ctx); 241398a9cb79SRichard Henderson 2414deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2415deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2416eed14219SRichard Henderson 2417deee69a1SRichard Henderson if (a->imm) { 2418e5d487c9SRichard Henderson level = tcg_constant_i32(a->ri & 3); 241998a9cb79SRichard Henderson } else { 2420eed14219SRichard Henderson level = tcg_temp_new_i32(); 24216fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2422eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 242398a9cb79SRichard Henderson } 242429dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2425eed14219SRichard Henderson 2426ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2427eed14219SRichard Henderson 2428deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 242931234768SRichard Henderson return nullify_end(ctx); 243098a9cb79SRichard Henderson } 243198a9cb79SRichard Henderson 2432deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 24338d6ae7fbSRichard Henderson { 24348577f354SRichard Henderson if (ctx->is_pa20) { 24358577f354SRichard Henderson return false; 24368577f354SRichard Henderson } 2437deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2438deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24396fd0c7bcSRichard Henderson TCGv_i64 addr; 24406fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 24418d6ae7fbSRichard Henderson 24428d6ae7fbSRichard Henderson nullify_over(ctx); 24438d6ae7fbSRichard Henderson 2444deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2445deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2446deee69a1SRichard Henderson if (a->addr) { 24478577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 24488d6ae7fbSRichard Henderson } else { 24498577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 24508d6ae7fbSRichard Henderson } 24518d6ae7fbSRichard Henderson 245232dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 245332dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 245431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 245531234768SRichard Henderson } 245631234768SRichard Henderson return nullify_end(ctx); 2457deee69a1SRichard Henderson #endif 24588d6ae7fbSRichard Henderson } 245963300a00SRichard Henderson 2460eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 246163300a00SRichard Henderson { 2462deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2463deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24646fd0c7bcSRichard Henderson TCGv_i64 addr; 24656fd0c7bcSRichard Henderson TCGv_i64 ofs; 246663300a00SRichard Henderson 246763300a00SRichard Henderson nullify_over(ctx); 246863300a00SRichard Henderson 2469deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2470eb25d10fSHelge Deller 2471eb25d10fSHelge Deller /* 2472eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2473eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2474eb25d10fSHelge Deller */ 2475eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2476eb25d10fSHelge Deller if (ctx->is_pa20) { 2477eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 247863300a00SRichard Henderson } 2479eb25d10fSHelge Deller 2480eb25d10fSHelge Deller if (local) { 2481eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 248263300a00SRichard Henderson } else { 2483ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 248463300a00SRichard Henderson } 248563300a00SRichard Henderson 2486eb25d10fSHelge Deller if (a->m) { 2487eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2488eb25d10fSHelge Deller } 2489eb25d10fSHelge Deller 2490eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2491eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2492eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2493eb25d10fSHelge Deller } 2494eb25d10fSHelge Deller return nullify_end(ctx); 2495eb25d10fSHelge Deller #endif 2496eb25d10fSHelge Deller } 2497eb25d10fSHelge Deller 2498eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2499eb25d10fSHelge Deller { 2500eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2501eb25d10fSHelge Deller } 2502eb25d10fSHelge Deller 2503eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2504eb25d10fSHelge Deller { 2505eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2506eb25d10fSHelge Deller } 2507eb25d10fSHelge Deller 2508eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2509eb25d10fSHelge Deller { 2510eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2511eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2512eb25d10fSHelge Deller nullify_over(ctx); 2513eb25d10fSHelge Deller 2514eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2515eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2516eb25d10fSHelge Deller 251763300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 251832dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 251931234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 252031234768SRichard Henderson } 252131234768SRichard Henderson return nullify_end(ctx); 2522deee69a1SRichard Henderson #endif 252363300a00SRichard Henderson } 25242dfcca9fSRichard Henderson 25256797c315SNick Hudson /* 25266797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 25276797c315SNick Hudson * See 25286797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 25296797c315SNick Hudson * page 13-9 (195/206) 25306797c315SNick Hudson */ 25316797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 25326797c315SNick Hudson { 25338577f354SRichard Henderson if (ctx->is_pa20) { 25348577f354SRichard Henderson return false; 25358577f354SRichard Henderson } 25366797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 25376797c315SNick Hudson #ifndef CONFIG_USER_ONLY 25386fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 25396fd0c7bcSRichard Henderson TCGv_i64 reg; 25406797c315SNick Hudson 25416797c315SNick Hudson nullify_over(ctx); 25426797c315SNick Hudson 25436797c315SNick Hudson /* 25446797c315SNick Hudson * FIXME: 25456797c315SNick Hudson * if (not (pcxl or pcxl2)) 25466797c315SNick Hudson * return gen_illegal(ctx); 25476797c315SNick Hudson */ 25486797c315SNick Hudson 25496fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 25506fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 25516fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 25526797c315SNick Hudson 2553ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 25546797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 25556797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2556ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 25576797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 25586797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 25596797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2560d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 25616797c315SNick Hudson 25626797c315SNick Hudson reg = load_gpr(ctx, a->r); 25636797c315SNick Hudson if (a->addr) { 25648577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 25656797c315SNick Hudson } else { 25668577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 25676797c315SNick Hudson } 25686797c315SNick Hudson 25696797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 25706797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 25716797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 25726797c315SNick Hudson } 25736797c315SNick Hudson return nullify_end(ctx); 25746797c315SNick Hudson #endif 25756797c315SNick Hudson } 25766797c315SNick Hudson 25778577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 25788577f354SRichard Henderson { 25798577f354SRichard Henderson if (!ctx->is_pa20) { 25808577f354SRichard Henderson return false; 25818577f354SRichard Henderson } 25828577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 25838577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 25848577f354SRichard Henderson nullify_over(ctx); 25858577f354SRichard Henderson { 25868577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 25878577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 25888577f354SRichard Henderson 25898577f354SRichard Henderson if (a->data) { 25908577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 25918577f354SRichard Henderson } else { 25928577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 25938577f354SRichard Henderson } 25948577f354SRichard Henderson } 25958577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 25968577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 25978577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 25988577f354SRichard Henderson } 25998577f354SRichard Henderson return nullify_end(ctx); 26008577f354SRichard Henderson #endif 26018577f354SRichard Henderson } 26028577f354SRichard Henderson 2603deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 26042dfcca9fSRichard Henderson { 2605deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2606deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 26076fd0c7bcSRichard Henderson TCGv_i64 vaddr; 26086fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 26092dfcca9fSRichard Henderson 26102dfcca9fSRichard Henderson nullify_over(ctx); 26112dfcca9fSRichard Henderson 2612deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 26132dfcca9fSRichard Henderson 2614aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2615ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 26162dfcca9fSRichard Henderson 26172dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2618deee69a1SRichard Henderson if (a->m) { 2619deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 26202dfcca9fSRichard Henderson } 2621deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 26222dfcca9fSRichard Henderson 262331234768SRichard Henderson return nullify_end(ctx); 2624deee69a1SRichard Henderson #endif 26252dfcca9fSRichard Henderson } 262643a97b81SRichard Henderson 2627deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 262843a97b81SRichard Henderson { 262943a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 263043a97b81SRichard Henderson 263143a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 263243a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 263343a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 263443a97b81SRichard Henderson since the entire address space is coherent. */ 2635a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 263643a97b81SRichard Henderson 2637*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 263831234768SRichard Henderson return true; 263943a97b81SRichard Henderson } 264098a9cb79SRichard Henderson 2641faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2642b2167459SRichard Henderson { 26430c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2644b2167459SRichard Henderson } 2645b2167459SRichard Henderson 2646faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2647b2167459SRichard Henderson { 26480c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2649b2167459SRichard Henderson } 2650b2167459SRichard Henderson 2651faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2652b2167459SRichard Henderson { 26530c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2654b2167459SRichard Henderson } 2655b2167459SRichard Henderson 2656faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2657b2167459SRichard Henderson { 26580c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 26590c982a28SRichard Henderson } 2660b2167459SRichard Henderson 2661faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 26620c982a28SRichard Henderson { 26630c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 26640c982a28SRichard Henderson } 26650c982a28SRichard Henderson 266663c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 26670c982a28SRichard Henderson { 26680c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 26690c982a28SRichard Henderson } 26700c982a28SRichard Henderson 267163c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 26720c982a28SRichard Henderson { 26730c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 26740c982a28SRichard Henderson } 26750c982a28SRichard Henderson 267663c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 26770c982a28SRichard Henderson { 26780c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 26790c982a28SRichard Henderson } 26800c982a28SRichard Henderson 268163c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 26820c982a28SRichard Henderson { 26830c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 26840c982a28SRichard Henderson } 26850c982a28SRichard Henderson 268663c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 26870c982a28SRichard Henderson { 26880c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 26890c982a28SRichard Henderson } 26900c982a28SRichard Henderson 269163c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 26920c982a28SRichard Henderson { 26930c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 26940c982a28SRichard Henderson } 26950c982a28SRichard Henderson 2696fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 26970c982a28SRichard Henderson { 26986fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 26990c982a28SRichard Henderson } 27000c982a28SRichard Henderson 2701fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 27020c982a28SRichard Henderson { 27036fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 27040c982a28SRichard Henderson } 27050c982a28SRichard Henderson 2706fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 27070c982a28SRichard Henderson { 27080c982a28SRichard Henderson if (a->cf == 0) { 27090c982a28SRichard Henderson unsigned r2 = a->r2; 27100c982a28SRichard Henderson unsigned r1 = a->r1; 27110c982a28SRichard Henderson unsigned rt = a->t; 27120c982a28SRichard Henderson 27137aee8189SRichard Henderson if (rt == 0) { /* NOP */ 2714*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 27157aee8189SRichard Henderson return true; 27167aee8189SRichard Henderson } 27177aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2718b2167459SRichard Henderson if (r1 == 0) { 27196fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 27206fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2721b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2722b2167459SRichard Henderson } else { 2723b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2724b2167459SRichard Henderson } 2725*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 272631234768SRichard Henderson return true; 2727b2167459SRichard Henderson } 27287aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 27297aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 27307aee8189SRichard Henderson * 27317aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 27327aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 27337aee8189SRichard Henderson * currently implemented as idle. 27347aee8189SRichard Henderson */ 27357aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 27367aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 27377aee8189SRichard Henderson until the next timer interrupt. */ 27387aee8189SRichard Henderson nullify_over(ctx); 27397aee8189SRichard Henderson 27407aee8189SRichard Henderson /* Advance the instruction queue. */ 2741bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_b, NULL); 27427aee8189SRichard Henderson nullify_set(ctx, 0); 27437aee8189SRichard Henderson 27447aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2745ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 274629dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 27477aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 27487aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 27497aee8189SRichard Henderson 27507aee8189SRichard Henderson return nullify_end(ctx); 27517aee8189SRichard Henderson } 27527aee8189SRichard Henderson #endif 27537aee8189SRichard Henderson } 27546fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 27557aee8189SRichard Henderson } 2756b2167459SRichard Henderson 2757fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2758b2167459SRichard Henderson { 27596fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 27600c982a28SRichard Henderson } 27610c982a28SRichard Henderson 2762345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 27630c982a28SRichard Henderson { 27646fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2765b2167459SRichard Henderson 27660c982a28SRichard Henderson if (a->cf) { 2767b2167459SRichard Henderson nullify_over(ctx); 2768b2167459SRichard Henderson } 27690c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 27700c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2771345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 277231234768SRichard Henderson return nullify_end(ctx); 2773b2167459SRichard Henderson } 2774b2167459SRichard Henderson 2775af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2776b2167459SRichard Henderson { 277746bb3d46SRichard Henderson TCGv_i64 tcg_r1, tcg_r2, dest; 2778b2167459SRichard Henderson 27790c982a28SRichard Henderson if (a->cf) { 2780b2167459SRichard Henderson nullify_over(ctx); 2781b2167459SRichard Henderson } 278246bb3d46SRichard Henderson 27830c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 27840c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 278546bb3d46SRichard Henderson dest = dest_gpr(ctx, a->t); 278646bb3d46SRichard Henderson 278746bb3d46SRichard Henderson tcg_gen_xor_i64(dest, tcg_r1, tcg_r2); 278846bb3d46SRichard Henderson save_gpr(ctx, a->t, dest); 278946bb3d46SRichard Henderson 279046bb3d46SRichard Henderson ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest); 279131234768SRichard Henderson return nullify_end(ctx); 2792b2167459SRichard Henderson } 2793b2167459SRichard Henderson 2794af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2795b2167459SRichard Henderson { 27966fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2797b2167459SRichard Henderson 2798ababac16SRichard Henderson if (a->cf == 0) { 2799ababac16SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2800ababac16SRichard Henderson tmp = dest_gpr(ctx, a->t); 2801ababac16SRichard Henderson 2802ababac16SRichard Henderson if (a->r1 == 0) { 2803ababac16SRichard Henderson /* UADDCM r0,src,dst is the common idiom for dst = ~src. */ 2804ababac16SRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 2805ababac16SRichard Henderson } else { 2806ababac16SRichard Henderson /* 2807ababac16SRichard Henderson * Recall that r1 - r2 == r1 + ~r2 + 1. 2808ababac16SRichard Henderson * Thus r1 + ~r2 == r1 - r2 - 1, 2809ababac16SRichard Henderson * which does not require an extra temporary. 2810ababac16SRichard Henderson */ 2811ababac16SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 2812ababac16SRichard Henderson tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2); 2813ababac16SRichard Henderson tcg_gen_subi_i64(tmp, tmp, 1); 2814b2167459SRichard Henderson } 2815ababac16SRichard Henderson save_gpr(ctx, a->t, tmp); 2816*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 2817ababac16SRichard Henderson return true; 2818ababac16SRichard Henderson } 2819ababac16SRichard Henderson 2820ababac16SRichard Henderson nullify_over(ctx); 28210c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 28220c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2823aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 28246fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 282546bb3d46SRichard Henderson do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true); 282631234768SRichard Henderson return nullify_end(ctx); 2827b2167459SRichard Henderson } 2828b2167459SRichard Henderson 2829af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2830b2167459SRichard Henderson { 28310c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 28320c982a28SRichard Henderson } 28330c982a28SRichard Henderson 2834af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 28350c982a28SRichard Henderson { 28360c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 28370c982a28SRichard Henderson } 28380c982a28SRichard Henderson 2839af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 28400c982a28SRichard Henderson { 28416fd0c7bcSRichard Henderson TCGv_i64 tmp; 2842b2167459SRichard Henderson 2843b2167459SRichard Henderson nullify_over(ctx); 2844b2167459SRichard Henderson 2845aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2846d0ae87a2SRichard Henderson tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4); 2847b2167459SRichard Henderson if (!is_i) { 28486fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2849b2167459SRichard Henderson } 28506fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 28516fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 285246bb3d46SRichard Henderson do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp, 285346bb3d46SRichard Henderson a->cf, a->d, false, is_i); 285431234768SRichard Henderson return nullify_end(ctx); 2855b2167459SRichard Henderson } 2856b2167459SRichard Henderson 2857af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2858b2167459SRichard Henderson { 28590c982a28SRichard Henderson return do_dcor(ctx, a, false); 28600c982a28SRichard Henderson } 28610c982a28SRichard Henderson 2862af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 28630c982a28SRichard Henderson { 28640c982a28SRichard Henderson return do_dcor(ctx, a, true); 28650c982a28SRichard Henderson } 28660c982a28SRichard Henderson 28670c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 28680c982a28SRichard Henderson { 2869a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 2870b2167459SRichard Henderson 2871b2167459SRichard Henderson nullify_over(ctx); 2872b2167459SRichard Henderson 28730c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 28740c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2875b2167459SRichard Henderson 2876aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2877aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2878aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2879aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2880b2167459SRichard Henderson 2881b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 28826fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 28836fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2884b2167459SRichard Henderson 288572ca8753SRichard Henderson /* 288672ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 288772ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 288872ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 288972ca8753SRichard Henderson * proper inputs to the addition without movcond. 289072ca8753SRichard Henderson */ 28916fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 28926fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 28936fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 289472ca8753SRichard Henderson 2895a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2896a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2897a4db4a78SRichard Henderson addc, ctx->zero); 2898b2167459SRichard Henderson 2899b2167459SRichard Henderson /* Write back the result register. */ 29000c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2901b2167459SRichard Henderson 2902b2167459SRichard Henderson /* Write back PSW[CB]. */ 29036fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 29046fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2905b2167459SRichard Henderson 2906f8f5986eSRichard Henderson /* 2907f8f5986eSRichard Henderson * Write back PSW[V] for the division step. 2908f8f5986eSRichard Henderson * Shift cb{8} from where it lives in bit 32 to bit 31, 2909f8f5986eSRichard Henderson * so that it overlaps r2{32} in bit 31. 2910f8f5986eSRichard Henderson */ 2911f8f5986eSRichard Henderson tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1); 29126fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2913b2167459SRichard Henderson 2914b2167459SRichard Henderson /* Install the new nullification. */ 29150c982a28SRichard Henderson if (a->cf) { 2916f8f5986eSRichard Henderson TCGv_i64 sv = NULL, uv = NULL; 2917b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2918f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false); 2919f8f5986eSRichard Henderson } else if (cond_need_cb(a->cf >> 1)) { 2920f8f5986eSRichard Henderson uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false); 2921b2167459SRichard Henderson } 2922f8f5986eSRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv); 2923b2167459SRichard Henderson } 2924b2167459SRichard Henderson 292531234768SRichard Henderson return nullify_end(ctx); 2926b2167459SRichard Henderson } 2927b2167459SRichard Henderson 29280588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2929b2167459SRichard Henderson { 29300588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 29310588e061SRichard Henderson } 29320588e061SRichard Henderson 29330588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 29340588e061SRichard Henderson { 29350588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 29360588e061SRichard Henderson } 29370588e061SRichard Henderson 29380588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 29390588e061SRichard Henderson { 29400588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 29410588e061SRichard Henderson } 29420588e061SRichard Henderson 29430588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 29440588e061SRichard Henderson { 29450588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 29460588e061SRichard Henderson } 29470588e061SRichard Henderson 29480588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 29490588e061SRichard Henderson { 29500588e061SRichard Henderson return do_sub_imm(ctx, a, false); 29510588e061SRichard Henderson } 29520588e061SRichard Henderson 29530588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 29540588e061SRichard Henderson { 29550588e061SRichard Henderson return do_sub_imm(ctx, a, true); 29560588e061SRichard Henderson } 29570588e061SRichard Henderson 2958345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 29590588e061SRichard Henderson { 29606fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 2961b2167459SRichard Henderson 29620588e061SRichard Henderson if (a->cf) { 2963b2167459SRichard Henderson nullify_over(ctx); 2964b2167459SRichard Henderson } 2965b2167459SRichard Henderson 29666fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 29670588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 2968345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2969b2167459SRichard Henderson 297031234768SRichard Henderson return nullify_end(ctx); 2971b2167459SRichard Henderson } 2972b2167459SRichard Henderson 29730843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 29740843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 29750843563fSRichard Henderson { 29760843563fSRichard Henderson TCGv_i64 r1, r2, dest; 29770843563fSRichard Henderson 29780843563fSRichard Henderson if (!ctx->is_pa20) { 29790843563fSRichard Henderson return false; 29800843563fSRichard Henderson } 29810843563fSRichard Henderson 29820843563fSRichard Henderson nullify_over(ctx); 29830843563fSRichard Henderson 29840843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 29850843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 29860843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 29870843563fSRichard Henderson 29880843563fSRichard Henderson fn(dest, r1, r2); 29890843563fSRichard Henderson save_gpr(ctx, a->t, dest); 29900843563fSRichard Henderson 29910843563fSRichard Henderson return nullify_end(ctx); 29920843563fSRichard Henderson } 29930843563fSRichard Henderson 2994151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 2995151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 2996151f309bSRichard Henderson { 2997151f309bSRichard Henderson TCGv_i64 r, dest; 2998151f309bSRichard Henderson 2999151f309bSRichard Henderson if (!ctx->is_pa20) { 3000151f309bSRichard Henderson return false; 3001151f309bSRichard Henderson } 3002151f309bSRichard Henderson 3003151f309bSRichard Henderson nullify_over(ctx); 3004151f309bSRichard Henderson 3005151f309bSRichard Henderson r = load_gpr(ctx, a->r); 3006151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 3007151f309bSRichard Henderson 3008151f309bSRichard Henderson fn(dest, r, a->i); 3009151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 3010151f309bSRichard Henderson 3011151f309bSRichard Henderson return nullify_end(ctx); 3012151f309bSRichard Henderson } 3013151f309bSRichard Henderson 30143bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 30153bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 30163bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 30173bbb8e48SRichard Henderson { 30183bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 30193bbb8e48SRichard Henderson 30203bbb8e48SRichard Henderson if (!ctx->is_pa20) { 30213bbb8e48SRichard Henderson return false; 30223bbb8e48SRichard Henderson } 30233bbb8e48SRichard Henderson 30243bbb8e48SRichard Henderson nullify_over(ctx); 30253bbb8e48SRichard Henderson 30263bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 30273bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 30283bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 30293bbb8e48SRichard Henderson 30303bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 30313bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 30323bbb8e48SRichard Henderson 30333bbb8e48SRichard Henderson return nullify_end(ctx); 30343bbb8e48SRichard Henderson } 30353bbb8e48SRichard Henderson 30360843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 30370843563fSRichard Henderson { 30380843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 30390843563fSRichard Henderson } 30400843563fSRichard Henderson 30410843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 30420843563fSRichard Henderson { 30430843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 30440843563fSRichard Henderson } 30450843563fSRichard Henderson 30460843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 30470843563fSRichard Henderson { 30480843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 30490843563fSRichard Henderson } 30500843563fSRichard Henderson 30511b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 30521b3cb7c8SRichard Henderson { 30531b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 30541b3cb7c8SRichard Henderson } 30551b3cb7c8SRichard Henderson 3056151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 3057151f309bSRichard Henderson { 3058151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 3059151f309bSRichard Henderson } 3060151f309bSRichard Henderson 3061151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 3062151f309bSRichard Henderson { 3063151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 3064151f309bSRichard Henderson } 3065151f309bSRichard Henderson 3066151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 3067151f309bSRichard Henderson { 3068151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 3069151f309bSRichard Henderson } 3070151f309bSRichard Henderson 30713bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 30723bbb8e48SRichard Henderson { 30733bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 30743bbb8e48SRichard Henderson } 30753bbb8e48SRichard Henderson 30763bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 30773bbb8e48SRichard Henderson { 30783bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 30793bbb8e48SRichard Henderson } 30803bbb8e48SRichard Henderson 308110c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 308210c9e58dSRichard Henderson { 308310c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 308410c9e58dSRichard Henderson } 308510c9e58dSRichard Henderson 308610c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 308710c9e58dSRichard Henderson { 308810c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 308910c9e58dSRichard Henderson } 309010c9e58dSRichard Henderson 309110c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 309210c9e58dSRichard Henderson { 309310c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 309410c9e58dSRichard Henderson } 309510c9e58dSRichard Henderson 3096c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3097c2a7ee3fSRichard Henderson { 3098c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 3099c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3100c2a7ee3fSRichard Henderson 3101c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 3102c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 3103c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 3104c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3105c2a7ee3fSRichard Henderson } 3106c2a7ee3fSRichard Henderson 3107c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 3108c2a7ee3fSRichard Henderson { 3109c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 3110c2a7ee3fSRichard Henderson } 3111c2a7ee3fSRichard Henderson 3112c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3113c2a7ee3fSRichard Henderson { 3114c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 3115c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3116c2a7ee3fSRichard Henderson 3117c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 3118c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 3119c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 3120c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3121c2a7ee3fSRichard Henderson } 3122c2a7ee3fSRichard Henderson 3123c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 3124c2a7ee3fSRichard Henderson { 3125c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 3126c2a7ee3fSRichard Henderson } 3127c2a7ee3fSRichard Henderson 3128c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3129c2a7ee3fSRichard Henderson { 3130c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3131c2a7ee3fSRichard Henderson 3132c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 3133c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 3134c2a7ee3fSRichard Henderson } 3135c2a7ee3fSRichard Henderson 3136c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 3137c2a7ee3fSRichard Henderson { 3138c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 3139c2a7ee3fSRichard Henderson } 3140c2a7ee3fSRichard Henderson 3141c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3142c2a7ee3fSRichard Henderson { 3143c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 3144c2a7ee3fSRichard Henderson } 3145c2a7ee3fSRichard Henderson 3146c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 3147c2a7ee3fSRichard Henderson { 3148c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 3149c2a7ee3fSRichard Henderson } 3150c2a7ee3fSRichard Henderson 31514e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 31524e7abdb1SRichard Henderson { 31534e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 31544e7abdb1SRichard Henderson 31554e7abdb1SRichard Henderson if (!ctx->is_pa20) { 31564e7abdb1SRichard Henderson return false; 31574e7abdb1SRichard Henderson } 31584e7abdb1SRichard Henderson 31594e7abdb1SRichard Henderson nullify_over(ctx); 31604e7abdb1SRichard Henderson 31614e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 31624e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 31634e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 31644e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 31654e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 31664e7abdb1SRichard Henderson 31674e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 31684e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 31694e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 31704e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 31714e7abdb1SRichard Henderson 31724e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 31734e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 31744e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 31754e7abdb1SRichard Henderson 31764e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 31774e7abdb1SRichard Henderson return nullify_end(ctx); 31784e7abdb1SRichard Henderson } 31794e7abdb1SRichard Henderson 31801cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 318196d6407fSRichard Henderson { 3182b5caa17cSRichard Henderson if (ctx->is_pa20) { 3183b5caa17cSRichard Henderson /* 3184b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3185b5caa17cSRichard Henderson * Any base modification still occurs. 3186b5caa17cSRichard Henderson */ 3187b5caa17cSRichard Henderson if (a->t == 0) { 3188b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3189b5caa17cSRichard Henderson } 3190b5caa17cSRichard Henderson } else if (a->size > MO_32) { 31910786a3b6SHelge Deller return gen_illegal(ctx); 3192c53e401eSRichard Henderson } 31931cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 31941cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 319596d6407fSRichard Henderson } 319696d6407fSRichard Henderson 31971cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 319896d6407fSRichard Henderson { 31991cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3200c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 32010786a3b6SHelge Deller return gen_illegal(ctx); 320296d6407fSRichard Henderson } 3203c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 32040786a3b6SHelge Deller } 320596d6407fSRichard Henderson 32061cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 320796d6407fSRichard Henderson { 3208b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3209a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 32106fd0c7bcSRichard Henderson TCGv_i64 addr; 321196d6407fSRichard Henderson 3212c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 321351416c4eSRichard Henderson return gen_illegal(ctx); 321451416c4eSRichard Henderson } 321551416c4eSRichard Henderson 321696d6407fSRichard Henderson nullify_over(ctx); 321796d6407fSRichard Henderson 32181cd012a5SRichard Henderson if (a->m) { 321986f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 322086f8d05fSRichard Henderson we see the result of the load. */ 3221aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 322296d6407fSRichard Henderson } else { 32231cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 322496d6407fSRichard Henderson } 322596d6407fSRichard Henderson 3226c3ea1996SSven Schnelle form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0, 322717fe594cSRichard Henderson a->disp, a->sp, a->m, MMU_DISABLED(ctx)); 3228b1af755cSRichard Henderson 3229b1af755cSRichard Henderson /* 3230b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3231b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3232b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3233b1af755cSRichard Henderson * 3234b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3235b1af755cSRichard Henderson * with the ,co completer. 3236b1af755cSRichard Henderson */ 3237b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3238b1af755cSRichard Henderson 3239a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3240b1af755cSRichard Henderson 32411cd012a5SRichard Henderson if (a->m) { 32421cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 324396d6407fSRichard Henderson } 32441cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 324596d6407fSRichard Henderson 324631234768SRichard Henderson return nullify_end(ctx); 324796d6407fSRichard Henderson } 324896d6407fSRichard Henderson 32491cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 325096d6407fSRichard Henderson { 32516fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 32526fd0c7bcSRichard Henderson TCGv_i64 addr; 325396d6407fSRichard Henderson 325496d6407fSRichard Henderson nullify_over(ctx); 325596d6407fSRichard Henderson 32561cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 325717fe594cSRichard Henderson MMU_DISABLED(ctx)); 32581cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 32591cd012a5SRichard Henderson if (a->a) { 3260f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3261ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3262f9f46db4SEmilio G. Cota } else { 3263ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3264f9f46db4SEmilio G. Cota } 3265f9f46db4SEmilio G. Cota } else { 3266f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3267ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 326896d6407fSRichard Henderson } else { 3269ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 327096d6407fSRichard Henderson } 3271f9f46db4SEmilio G. Cota } 32721cd012a5SRichard Henderson if (a->m) { 32736fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 32741cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 327596d6407fSRichard Henderson } 327696d6407fSRichard Henderson 327731234768SRichard Henderson return nullify_end(ctx); 327896d6407fSRichard Henderson } 327996d6407fSRichard Henderson 328025460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 328125460fc5SRichard Henderson { 32826fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 32836fd0c7bcSRichard Henderson TCGv_i64 addr; 328425460fc5SRichard Henderson 328525460fc5SRichard Henderson if (!ctx->is_pa20) { 328625460fc5SRichard Henderson return false; 328725460fc5SRichard Henderson } 328825460fc5SRichard Henderson nullify_over(ctx); 328925460fc5SRichard Henderson 329025460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 329117fe594cSRichard Henderson MMU_DISABLED(ctx)); 329225460fc5SRichard Henderson val = load_gpr(ctx, a->r); 329325460fc5SRichard Henderson if (a->a) { 329425460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 329525460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 329625460fc5SRichard Henderson } else { 329725460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 329825460fc5SRichard Henderson } 329925460fc5SRichard Henderson } else { 330025460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 330125460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 330225460fc5SRichard Henderson } else { 330325460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 330425460fc5SRichard Henderson } 330525460fc5SRichard Henderson } 330625460fc5SRichard Henderson if (a->m) { 33076fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 330825460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 330925460fc5SRichard Henderson } 331025460fc5SRichard Henderson 331125460fc5SRichard Henderson return nullify_end(ctx); 331225460fc5SRichard Henderson } 331325460fc5SRichard Henderson 33141cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3315d0a851ccSRichard Henderson { 3316d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3317d0a851ccSRichard Henderson 3318d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3319451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 33201cd012a5SRichard Henderson trans_ld(ctx, a); 3321d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 332231234768SRichard Henderson return true; 3323d0a851ccSRichard Henderson } 3324d0a851ccSRichard Henderson 33251cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3326d0a851ccSRichard Henderson { 3327d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3328d0a851ccSRichard Henderson 3329d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3330451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 33311cd012a5SRichard Henderson trans_st(ctx, a); 3332d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 333331234768SRichard Henderson return true; 3334d0a851ccSRichard Henderson } 333595412a61SRichard Henderson 33360588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3337b2167459SRichard Henderson { 33386fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3339b2167459SRichard Henderson 33406fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 33410588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3342*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 334331234768SRichard Henderson return true; 3344b2167459SRichard Henderson } 3345b2167459SRichard Henderson 33460588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3347b2167459SRichard Henderson { 33486fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 33496fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3350b2167459SRichard Henderson 33516fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3352b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3353*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 335431234768SRichard Henderson return true; 3355b2167459SRichard Henderson } 3356b2167459SRichard Henderson 33570588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3358b2167459SRichard Henderson { 33596fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3360b2167459SRichard Henderson 3361b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3362d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 33630588e061SRichard Henderson if (a->b == 0) { 33646fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3365b2167459SRichard Henderson } else { 33666fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3367b2167459SRichard Henderson } 33680588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3369*e0137378SRichard Henderson ctx->null_cond = cond_make_f(); 337031234768SRichard Henderson return true; 3371b2167459SRichard Henderson } 3372b2167459SRichard Henderson 33736fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3374e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 337598cd9ca7SRichard Henderson { 33766fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 337798cd9ca7SRichard Henderson DisasCond cond; 337898cd9ca7SRichard Henderson 337998cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3380aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 338198cd9ca7SRichard Henderson 33826fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 338398cd9ca7SRichard Henderson 3384f764718dSRichard Henderson sv = NULL; 3385b47a4a02SSven Schnelle if (cond_need_sv(c)) { 338698cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 338798cd9ca7SRichard Henderson } 338898cd9ca7SRichard Henderson 33894fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 339001afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 339198cd9ca7SRichard Henderson } 339298cd9ca7SRichard Henderson 339301afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 339498cd9ca7SRichard Henderson { 3395e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3396e9efd4bcSRichard Henderson return false; 3397e9efd4bcSRichard Henderson } 339801afb7beSRichard Henderson nullify_over(ctx); 3399e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3400e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 340101afb7beSRichard Henderson } 340201afb7beSRichard Henderson 340301afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 340401afb7beSRichard Henderson { 3405c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3406c65c3ee1SRichard Henderson return false; 3407c65c3ee1SRichard Henderson } 340801afb7beSRichard Henderson nullify_over(ctx); 34096fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3410c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 341101afb7beSRichard Henderson } 341201afb7beSRichard Henderson 34136fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 341401afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 341501afb7beSRichard Henderson { 34166fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 341798cd9ca7SRichard Henderson DisasCond cond; 3418bdcccc17SRichard Henderson bool d = false; 341998cd9ca7SRichard Henderson 3420f25d3160SRichard Henderson /* 3421f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3422f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3423f25d3160SRichard Henderson */ 3424f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3425f25d3160SRichard Henderson d = c >= 5; 3426f25d3160SRichard Henderson if (d) { 3427f25d3160SRichard Henderson c &= 3; 3428f25d3160SRichard Henderson } 3429f25d3160SRichard Henderson } 3430f25d3160SRichard Henderson 343198cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3432aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3433f764718dSRichard Henderson sv = NULL; 3434bdcccc17SRichard Henderson cb_cond = NULL; 343598cd9ca7SRichard Henderson 3436b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3437aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3438aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3439bdcccc17SRichard Henderson 34406fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 34416fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 34426fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 34436fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3444bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3445b47a4a02SSven Schnelle } else { 34466fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3447b47a4a02SSven Schnelle } 3448b47a4a02SSven Schnelle if (cond_need_sv(c)) { 3449f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d); 345098cd9ca7SRichard Henderson } 345198cd9ca7SRichard Henderson 3452a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 345343675d20SSven Schnelle save_gpr(ctx, r, dest); 345401afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 345598cd9ca7SRichard Henderson } 345698cd9ca7SRichard Henderson 345701afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 345898cd9ca7SRichard Henderson { 345901afb7beSRichard Henderson nullify_over(ctx); 346001afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 346101afb7beSRichard Henderson } 346201afb7beSRichard Henderson 346301afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 346401afb7beSRichard Henderson { 346501afb7beSRichard Henderson nullify_over(ctx); 34666fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 346701afb7beSRichard Henderson } 346801afb7beSRichard Henderson 346901afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 347001afb7beSRichard Henderson { 34716fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 347298cd9ca7SRichard Henderson DisasCond cond; 347398cd9ca7SRichard Henderson 347498cd9ca7SRichard Henderson nullify_over(ctx); 347598cd9ca7SRichard Henderson 3476aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 347701afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 347882d0c831SRichard Henderson if (a->d) { 347982d0c831SRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 348082d0c831SRichard Henderson } else { 34811e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 34826fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 34836fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 34841e9ab9fbSRichard Henderson } 348598cd9ca7SRichard Henderson 34864c42fd0dSRichard Henderson cond = cond_make_ti(a->c ? TCG_COND_GE : TCG_COND_LT, tmp, 0); 348701afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 348898cd9ca7SRichard Henderson } 348998cd9ca7SRichard Henderson 349001afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 349198cd9ca7SRichard Henderson { 349201afb7beSRichard Henderson DisasCond cond; 3493b041ec9dSRichard Henderson int p = a->p | (a->d ? 0 : 32); 349401afb7beSRichard Henderson 349501afb7beSRichard Henderson nullify_over(ctx); 3496b041ec9dSRichard Henderson cond = cond_make_vi(a->c ? TCG_COND_TSTEQ : TCG_COND_TSTNE, 3497b041ec9dSRichard Henderson load_gpr(ctx, a->r), 1ull << (63 - p)); 349801afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 349901afb7beSRichard Henderson } 350001afb7beSRichard Henderson 350101afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 350201afb7beSRichard Henderson { 35036fd0c7bcSRichard Henderson TCGv_i64 dest; 350498cd9ca7SRichard Henderson DisasCond cond; 350598cd9ca7SRichard Henderson 350698cd9ca7SRichard Henderson nullify_over(ctx); 350798cd9ca7SRichard Henderson 350801afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 350901afb7beSRichard Henderson if (a->r1 == 0) { 35106fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 351198cd9ca7SRichard Henderson } else { 35126fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 351398cd9ca7SRichard Henderson } 351498cd9ca7SRichard Henderson 35154fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 35164fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 351701afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 351801afb7beSRichard Henderson } 351901afb7beSRichard Henderson 352001afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 352101afb7beSRichard Henderson { 35226fd0c7bcSRichard Henderson TCGv_i64 dest; 352301afb7beSRichard Henderson DisasCond cond; 352401afb7beSRichard Henderson 352501afb7beSRichard Henderson nullify_over(ctx); 352601afb7beSRichard Henderson 352701afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 35286fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 352901afb7beSRichard Henderson 35304fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 35314fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 353201afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 353398cd9ca7SRichard Henderson } 353498cd9ca7SRichard Henderson 3535f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 35360b1347d2SRichard Henderson { 35376fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 35380b1347d2SRichard Henderson 3539f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3540f7b775a9SRichard Henderson return false; 3541f7b775a9SRichard Henderson } 354230878590SRichard Henderson if (a->c) { 35430b1347d2SRichard Henderson nullify_over(ctx); 35440b1347d2SRichard Henderson } 35450b1347d2SRichard Henderson 354630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3547f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 354830878590SRichard Henderson if (a->r1 == 0) { 3549f7b775a9SRichard Henderson if (a->d) { 35506fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3551f7b775a9SRichard Henderson } else { 3552aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3553f7b775a9SRichard Henderson 35546fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 35556fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 35566fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3557f7b775a9SRichard Henderson } 355830878590SRichard Henderson } else if (a->r1 == a->r2) { 3559f7b775a9SRichard Henderson if (a->d) { 35606fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3561f7b775a9SRichard Henderson } else { 35620b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3563e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3564e1d635e8SRichard Henderson 35656fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 35666fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3567f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3568e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 35696fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3570f7b775a9SRichard Henderson } 3571f7b775a9SRichard Henderson } else { 35726fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3573f7b775a9SRichard Henderson 3574f7b775a9SRichard Henderson if (a->d) { 3575aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3576aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3577f7b775a9SRichard Henderson 35786fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 3579a01491a2SHelge Deller tcg_gen_shl_i64(t, src1, n); 35806fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 3581a01491a2SHelge Deller tcg_gen_shr_i64(dest, src2, cpu_sar); 35826fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 35830b1347d2SRichard Henderson } else { 35840b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 35850b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 35860b1347d2SRichard Henderson 35876fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3588967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3589967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 35900b1347d2SRichard Henderson } 3591f7b775a9SRichard Henderson } 359230878590SRichard Henderson save_gpr(ctx, a->t, dest); 35930b1347d2SRichard Henderson 35940b1347d2SRichard Henderson /* Install the new nullification. */ 3595d37fad0aSSven Schnelle ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 359631234768SRichard Henderson return nullify_end(ctx); 35970b1347d2SRichard Henderson } 35980b1347d2SRichard Henderson 3599f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 36000b1347d2SRichard Henderson { 3601f7b775a9SRichard Henderson unsigned width, sa; 36026fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 36030b1347d2SRichard Henderson 3604f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3605f7b775a9SRichard Henderson return false; 3606f7b775a9SRichard Henderson } 360730878590SRichard Henderson if (a->c) { 36080b1347d2SRichard Henderson nullify_over(ctx); 36090b1347d2SRichard Henderson } 36100b1347d2SRichard Henderson 3611f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3612f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3613f7b775a9SRichard Henderson 361430878590SRichard Henderson dest = dest_gpr(ctx, a->t); 361530878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 361605bfd4dbSRichard Henderson if (a->r1 == 0) { 36176fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3618c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 36196fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3620f7b775a9SRichard Henderson } else { 3621f7b775a9SRichard Henderson assert(!a->d); 3622f7b775a9SRichard Henderson if (a->r1 == a->r2) { 36230b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 36246fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 36250b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 36266fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 36270b1347d2SRichard Henderson } else { 3628967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3629967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 36300b1347d2SRichard Henderson } 3631f7b775a9SRichard Henderson } 363230878590SRichard Henderson save_gpr(ctx, a->t, dest); 36330b1347d2SRichard Henderson 36340b1347d2SRichard Henderson /* Install the new nullification. */ 3635d37fad0aSSven Schnelle ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 363631234768SRichard Henderson return nullify_end(ctx); 36370b1347d2SRichard Henderson } 36380b1347d2SRichard Henderson 3639bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 36400b1347d2SRichard Henderson { 3641bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 36426fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 36430b1347d2SRichard Henderson 3644bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3645bd792da3SRichard Henderson return false; 3646bd792da3SRichard Henderson } 364730878590SRichard Henderson if (a->c) { 36480b1347d2SRichard Henderson nullify_over(ctx); 36490b1347d2SRichard Henderson } 36500b1347d2SRichard Henderson 365130878590SRichard Henderson dest = dest_gpr(ctx, a->t); 365230878590SRichard Henderson src = load_gpr(ctx, a->r); 3653aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 36540b1347d2SRichard Henderson 36550b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 36566fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 36576fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3658d781cb77SRichard Henderson 365930878590SRichard Henderson if (a->se) { 3660bd792da3SRichard Henderson if (!a->d) { 36616fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3662bd792da3SRichard Henderson src = dest; 3663bd792da3SRichard Henderson } 36646fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 36656fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 36660b1347d2SRichard Henderson } else { 3667bd792da3SRichard Henderson if (!a->d) { 36686fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3669bd792da3SRichard Henderson src = dest; 3670bd792da3SRichard Henderson } 36716fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 36726fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 36730b1347d2SRichard Henderson } 367430878590SRichard Henderson save_gpr(ctx, a->t, dest); 36750b1347d2SRichard Henderson 36760b1347d2SRichard Henderson /* Install the new nullification. */ 3677bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 367831234768SRichard Henderson return nullify_end(ctx); 36790b1347d2SRichard Henderson } 36800b1347d2SRichard Henderson 3681bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 36820b1347d2SRichard Henderson { 3683bd792da3SRichard Henderson unsigned len, cpos, width; 36846fd0c7bcSRichard Henderson TCGv_i64 dest, src; 36850b1347d2SRichard Henderson 3686bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3687bd792da3SRichard Henderson return false; 3688bd792da3SRichard Henderson } 368930878590SRichard Henderson if (a->c) { 36900b1347d2SRichard Henderson nullify_over(ctx); 36910b1347d2SRichard Henderson } 36920b1347d2SRichard Henderson 3693bd792da3SRichard Henderson len = a->len; 3694bd792da3SRichard Henderson width = a->d ? 64 : 32; 3695bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3696bd792da3SRichard Henderson if (cpos + len > width) { 3697bd792da3SRichard Henderson len = width - cpos; 3698bd792da3SRichard Henderson } 3699bd792da3SRichard Henderson 370030878590SRichard Henderson dest = dest_gpr(ctx, a->t); 370130878590SRichard Henderson src = load_gpr(ctx, a->r); 370230878590SRichard Henderson if (a->se) { 37036fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 37040b1347d2SRichard Henderson } else { 37056fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 37060b1347d2SRichard Henderson } 370730878590SRichard Henderson save_gpr(ctx, a->t, dest); 37080b1347d2SRichard Henderson 37090b1347d2SRichard Henderson /* Install the new nullification. */ 3710bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 371131234768SRichard Henderson return nullify_end(ctx); 37120b1347d2SRichard Henderson } 37130b1347d2SRichard Henderson 371472ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 37150b1347d2SRichard Henderson { 371672ae4f2bSRichard Henderson unsigned len, width; 3717c53e401eSRichard Henderson uint64_t mask0, mask1; 37186fd0c7bcSRichard Henderson TCGv_i64 dest; 37190b1347d2SRichard Henderson 372072ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 372172ae4f2bSRichard Henderson return false; 372272ae4f2bSRichard Henderson } 372330878590SRichard Henderson if (a->c) { 37240b1347d2SRichard Henderson nullify_over(ctx); 37250b1347d2SRichard Henderson } 372672ae4f2bSRichard Henderson 372772ae4f2bSRichard Henderson len = a->len; 372872ae4f2bSRichard Henderson width = a->d ? 64 : 32; 372972ae4f2bSRichard Henderson if (a->cpos + len > width) { 373072ae4f2bSRichard Henderson len = width - a->cpos; 37310b1347d2SRichard Henderson } 37320b1347d2SRichard Henderson 373330878590SRichard Henderson dest = dest_gpr(ctx, a->t); 373430878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 373530878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 37360b1347d2SRichard Henderson 373730878590SRichard Henderson if (a->nz) { 37386fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 37396fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 37406fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 37410b1347d2SRichard Henderson } else { 37426fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 37430b1347d2SRichard Henderson } 374430878590SRichard Henderson save_gpr(ctx, a->t, dest); 37450b1347d2SRichard Henderson 37460b1347d2SRichard Henderson /* Install the new nullification. */ 374772ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 374831234768SRichard Henderson return nullify_end(ctx); 37490b1347d2SRichard Henderson } 37500b1347d2SRichard Henderson 375172ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 37520b1347d2SRichard Henderson { 375330878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 375472ae4f2bSRichard Henderson unsigned len, width; 37556fd0c7bcSRichard Henderson TCGv_i64 dest, val; 37560b1347d2SRichard Henderson 375772ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 375872ae4f2bSRichard Henderson return false; 375972ae4f2bSRichard Henderson } 376030878590SRichard Henderson if (a->c) { 37610b1347d2SRichard Henderson nullify_over(ctx); 37620b1347d2SRichard Henderson } 376372ae4f2bSRichard Henderson 376472ae4f2bSRichard Henderson len = a->len; 376572ae4f2bSRichard Henderson width = a->d ? 64 : 32; 376672ae4f2bSRichard Henderson if (a->cpos + len > width) { 376772ae4f2bSRichard Henderson len = width - a->cpos; 37680b1347d2SRichard Henderson } 37690b1347d2SRichard Henderson 377030878590SRichard Henderson dest = dest_gpr(ctx, a->t); 377130878590SRichard Henderson val = load_gpr(ctx, a->r); 37720b1347d2SRichard Henderson if (rs == 0) { 37736fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 37740b1347d2SRichard Henderson } else { 37756fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 37760b1347d2SRichard Henderson } 377730878590SRichard Henderson save_gpr(ctx, a->t, dest); 37780b1347d2SRichard Henderson 37790b1347d2SRichard Henderson /* Install the new nullification. */ 378072ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 378131234768SRichard Henderson return nullify_end(ctx); 37820b1347d2SRichard Henderson } 37830b1347d2SRichard Henderson 378472ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 37856fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 37860b1347d2SRichard Henderson { 37870b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 378872ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 37896fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3790c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 37910b1347d2SRichard Henderson 37920b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3793aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3794aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37950b1347d2SRichard Henderson 37960b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 37976fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 37986fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 37990b1347d2SRichard Henderson 3800aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 38016fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 38026fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 38030b1347d2SRichard Henderson if (rs) { 38046fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 38056fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 38066fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 38076fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 38080b1347d2SRichard Henderson } else { 38096fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 38100b1347d2SRichard Henderson } 38110b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 38120b1347d2SRichard Henderson 38130b1347d2SRichard Henderson /* Install the new nullification. */ 381472ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 381531234768SRichard Henderson return nullify_end(ctx); 38160b1347d2SRichard Henderson } 38170b1347d2SRichard Henderson 381872ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 381930878590SRichard Henderson { 382072ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 382172ae4f2bSRichard Henderson return false; 382272ae4f2bSRichard Henderson } 3823a6deecceSSven Schnelle if (a->c) { 3824a6deecceSSven Schnelle nullify_over(ctx); 3825a6deecceSSven Schnelle } 382672ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 382772ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 382830878590SRichard Henderson } 382930878590SRichard Henderson 383072ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 383130878590SRichard Henderson { 383272ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 383372ae4f2bSRichard Henderson return false; 383472ae4f2bSRichard Henderson } 3835a6deecceSSven Schnelle if (a->c) { 3836a6deecceSSven Schnelle nullify_over(ctx); 3837a6deecceSSven Schnelle } 383872ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 38396fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 384030878590SRichard Henderson } 38410b1347d2SRichard Henderson 38428340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 384398cd9ca7SRichard Henderson { 3844019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY 3845bc921866SRichard Henderson ctx->iaq_j.space = tcg_temp_new_i64(); 3846bc921866SRichard Henderson load_spr(ctx, ctx->iaq_j.space, a->sp); 3847c301f34eSRichard Henderson #endif 3848019f4159SRichard Henderson 3849bc921866SRichard Henderson ctx->iaq_j.base = tcg_temp_new_i64(); 3850bc921866SRichard Henderson ctx->iaq_j.disp = 0; 3851bc921866SRichard Henderson 3852bc921866SRichard Henderson tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp); 3853bc921866SRichard Henderson ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base); 3854bc921866SRichard Henderson 3855bc921866SRichard Henderson return do_ibranch(ctx, a->l, true, a->n); 385698cd9ca7SRichard Henderson } 385798cd9ca7SRichard Henderson 38588340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 385998cd9ca7SRichard Henderson { 38602644f80bSRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 386198cd9ca7SRichard Henderson } 386298cd9ca7SRichard Henderson 38638340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 386443e05652SRichard Henderson { 3865bc921866SRichard Henderson int64_t disp = a->disp; 386643e05652SRichard Henderson 38676e5f5300SSven Schnelle nullify_over(ctx); 38686e5f5300SSven Schnelle 386943e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 387043e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 387143e05652SRichard Henderson * expensive to track. Real hardware will trap for 387243e05652SRichard Henderson * b gateway 387343e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 387443e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 387543e05652SRichard Henderson * diagnose the security hole 387643e05652SRichard Henderson * b gateway 387743e05652SRichard Henderson * b evil 387843e05652SRichard Henderson * in which instructions at evil would run with increased privs. 387943e05652SRichard Henderson */ 3880bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 388143e05652SRichard Henderson return gen_illegal(ctx); 388243e05652SRichard Henderson } 388343e05652SRichard Henderson 388443e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 388543e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 388694956d7bSPhilippe Mathieu-Daudé int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next); 388743e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 388843e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 388943e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 389043e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 389143e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 389243e05652SRichard Henderson if (type < 0) { 389331234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 389431234768SRichard Henderson return true; 389543e05652SRichard Henderson } 389643e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 389743e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 3898bc921866SRichard Henderson disp -= ctx->privilege; 3899bc921866SRichard Henderson disp += type - 4; 390043e05652SRichard Henderson } 390143e05652SRichard Henderson } else { 3902bc921866SRichard Henderson disp -= ctx->privilege; /* priv = 0 */ 390343e05652SRichard Henderson } 390443e05652SRichard Henderson #endif 390543e05652SRichard Henderson 39066e5f5300SSven Schnelle if (a->l) { 39076fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 39086e5f5300SSven Schnelle if (ctx->privilege < 3) { 39096fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 39106e5f5300SSven Schnelle } 39116fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 39126e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 39136e5f5300SSven Schnelle } 39146e5f5300SSven Schnelle 3915bc921866SRichard Henderson return do_dbranch(ctx, disp, 0, a->n); 391643e05652SRichard Henderson } 391743e05652SRichard Henderson 39188340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 391998cd9ca7SRichard Henderson { 3920b35aec85SRichard Henderson if (a->x) { 3921bc921866SRichard Henderson DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8); 3922bc921866SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 3923bc921866SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 3924bc921866SRichard Henderson 3925660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 3926bc921866SRichard Henderson copy_iaoq_entry(ctx, t0, &next); 3927bc921866SRichard Henderson tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3); 3928bc921866SRichard Henderson tcg_gen_add_i64(t0, t0, t1); 3929bc921866SRichard Henderson 3930bc921866SRichard Henderson ctx->iaq_j = iaqe_next_absv(ctx, t0); 3931bc921866SRichard Henderson return do_ibranch(ctx, a->l, false, a->n); 3932b35aec85SRichard Henderson } else { 3933b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 39342644f80bSRichard Henderson return do_dbranch(ctx, 0, a->l, a->n); 3935b35aec85SRichard Henderson } 393698cd9ca7SRichard Henderson } 393798cd9ca7SRichard Henderson 39388340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 393998cd9ca7SRichard Henderson { 39406fd0c7bcSRichard Henderson TCGv_i64 dest; 394198cd9ca7SRichard Henderson 39428340f534SRichard Henderson if (a->x == 0) { 39438340f534SRichard Henderson dest = load_gpr(ctx, a->b); 394498cd9ca7SRichard Henderson } else { 3945aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 39466fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 39476fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 394898cd9ca7SRichard Henderson } 3949660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 3950bc921866SRichard Henderson ctx->iaq_j = iaqe_next_absv(ctx, dest); 3951bc921866SRichard Henderson 3952bc921866SRichard Henderson return do_ibranch(ctx, 0, false, a->n); 395398cd9ca7SRichard Henderson } 395498cd9ca7SRichard Henderson 39558340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 395698cd9ca7SRichard Henderson { 3957019f4159SRichard Henderson TCGv_i64 b = load_gpr(ctx, a->b); 395898cd9ca7SRichard Henderson 3959019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY 3960bc921866SRichard Henderson ctx->iaq_j.space = space_select(ctx, 0, b); 3961c301f34eSRichard Henderson #endif 3962bc921866SRichard Henderson ctx->iaq_j.base = do_ibranch_priv(ctx, b); 3963bc921866SRichard Henderson ctx->iaq_j.disp = 0; 3964019f4159SRichard Henderson 3965bc921866SRichard Henderson return do_ibranch(ctx, a->l, false, a->n); 396698cd9ca7SRichard Henderson } 396798cd9ca7SRichard Henderson 3968a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 3969a8966ba7SRichard Henderson { 3970a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 3971a8966ba7SRichard Henderson return ctx->is_pa20; 3972a8966ba7SRichard Henderson } 3973a8966ba7SRichard Henderson 39741ca74648SRichard Henderson /* 39751ca74648SRichard Henderson * Float class 0 39761ca74648SRichard Henderson */ 3977ebe9383cSRichard Henderson 39781ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3979ebe9383cSRichard Henderson { 3980ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3981ebe9383cSRichard Henderson } 3982ebe9383cSRichard Henderson 398359f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 398459f8c04bSHelge Deller { 3985a300dad3SRichard Henderson uint64_t ret; 3986a300dad3SRichard Henderson 3987c53e401eSRichard Henderson if (ctx->is_pa20) { 3988a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 3989a300dad3SRichard Henderson } else { 3990a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 3991a300dad3SRichard Henderson } 3992a300dad3SRichard Henderson 399359f8c04bSHelge Deller nullify_over(ctx); 3994a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 399559f8c04bSHelge Deller return nullify_end(ctx); 399659f8c04bSHelge Deller } 399759f8c04bSHelge Deller 39981ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 39991ca74648SRichard Henderson { 40001ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 40011ca74648SRichard Henderson } 40021ca74648SRichard Henderson 4003ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4004ebe9383cSRichard Henderson { 4005ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 4006ebe9383cSRichard Henderson } 4007ebe9383cSRichard Henderson 40081ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 40091ca74648SRichard Henderson { 40101ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 40111ca74648SRichard Henderson } 40121ca74648SRichard Henderson 40131ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4014ebe9383cSRichard Henderson { 4015ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 4016ebe9383cSRichard Henderson } 4017ebe9383cSRichard Henderson 40181ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 40191ca74648SRichard Henderson { 40201ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 40211ca74648SRichard Henderson } 40221ca74648SRichard Henderson 4023ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4024ebe9383cSRichard Henderson { 4025ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 4026ebe9383cSRichard Henderson } 4027ebe9383cSRichard Henderson 40281ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 40291ca74648SRichard Henderson { 40301ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 40311ca74648SRichard Henderson } 40321ca74648SRichard Henderson 40331ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 40341ca74648SRichard Henderson { 40351ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 40361ca74648SRichard Henderson } 40371ca74648SRichard Henderson 40381ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 40391ca74648SRichard Henderson { 40401ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 40411ca74648SRichard Henderson } 40421ca74648SRichard Henderson 40431ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 40441ca74648SRichard Henderson { 40451ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 40461ca74648SRichard Henderson } 40471ca74648SRichard Henderson 40481ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 40491ca74648SRichard Henderson { 40501ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 40511ca74648SRichard Henderson } 40521ca74648SRichard Henderson 40531ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4054ebe9383cSRichard Henderson { 4055ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 4056ebe9383cSRichard Henderson } 4057ebe9383cSRichard Henderson 40581ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 40591ca74648SRichard Henderson { 40601ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 40611ca74648SRichard Henderson } 40621ca74648SRichard Henderson 4063ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4064ebe9383cSRichard Henderson { 4065ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 4066ebe9383cSRichard Henderson } 4067ebe9383cSRichard Henderson 40681ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 40691ca74648SRichard Henderson { 40701ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 40711ca74648SRichard Henderson } 40721ca74648SRichard Henderson 40731ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4074ebe9383cSRichard Henderson { 4075ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 4076ebe9383cSRichard Henderson } 4077ebe9383cSRichard Henderson 40781ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 40791ca74648SRichard Henderson { 40801ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 40811ca74648SRichard Henderson } 40821ca74648SRichard Henderson 4083ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4084ebe9383cSRichard Henderson { 4085ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4086ebe9383cSRichard Henderson } 4087ebe9383cSRichard Henderson 40881ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 40891ca74648SRichard Henderson { 40901ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 40911ca74648SRichard Henderson } 40921ca74648SRichard Henderson 40931ca74648SRichard Henderson /* 40941ca74648SRichard Henderson * Float class 1 40951ca74648SRichard Henderson */ 40961ca74648SRichard Henderson 40971ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 40981ca74648SRichard Henderson { 40991ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 41001ca74648SRichard Henderson } 41011ca74648SRichard Henderson 41021ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 41031ca74648SRichard Henderson { 41041ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 41051ca74648SRichard Henderson } 41061ca74648SRichard Henderson 41071ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 41081ca74648SRichard Henderson { 41091ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 41101ca74648SRichard Henderson } 41111ca74648SRichard Henderson 41121ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 41131ca74648SRichard Henderson { 41141ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 41151ca74648SRichard Henderson } 41161ca74648SRichard Henderson 41171ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 41181ca74648SRichard Henderson { 41191ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 41201ca74648SRichard Henderson } 41211ca74648SRichard Henderson 41221ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 41231ca74648SRichard Henderson { 41241ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 41251ca74648SRichard Henderson } 41261ca74648SRichard Henderson 41271ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 41281ca74648SRichard Henderson { 41291ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 41301ca74648SRichard Henderson } 41311ca74648SRichard Henderson 41321ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 41331ca74648SRichard Henderson { 41341ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 41351ca74648SRichard Henderson } 41361ca74648SRichard Henderson 41371ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 41381ca74648SRichard Henderson { 41391ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 41401ca74648SRichard Henderson } 41411ca74648SRichard Henderson 41421ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 41431ca74648SRichard Henderson { 41441ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 41451ca74648SRichard Henderson } 41461ca74648SRichard Henderson 41471ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 41481ca74648SRichard Henderson { 41491ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 41501ca74648SRichard Henderson } 41511ca74648SRichard Henderson 41521ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 41531ca74648SRichard Henderson { 41541ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 41551ca74648SRichard Henderson } 41561ca74648SRichard Henderson 41571ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 41581ca74648SRichard Henderson { 41591ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 41601ca74648SRichard Henderson } 41611ca74648SRichard Henderson 41621ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 41631ca74648SRichard Henderson { 41641ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 41651ca74648SRichard Henderson } 41661ca74648SRichard Henderson 41671ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 41681ca74648SRichard Henderson { 41691ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 41701ca74648SRichard Henderson } 41711ca74648SRichard Henderson 41721ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 41731ca74648SRichard Henderson { 41741ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 41751ca74648SRichard Henderson } 41761ca74648SRichard Henderson 41771ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 41781ca74648SRichard Henderson { 41791ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 41801ca74648SRichard Henderson } 41811ca74648SRichard Henderson 41821ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 41831ca74648SRichard Henderson { 41841ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 41851ca74648SRichard Henderson } 41861ca74648SRichard Henderson 41871ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 41881ca74648SRichard Henderson { 41891ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 41901ca74648SRichard Henderson } 41911ca74648SRichard Henderson 41921ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 41931ca74648SRichard Henderson { 41941ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 41951ca74648SRichard Henderson } 41961ca74648SRichard Henderson 41971ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 41981ca74648SRichard Henderson { 41991ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 42001ca74648SRichard Henderson } 42011ca74648SRichard Henderson 42021ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 42031ca74648SRichard Henderson { 42041ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 42051ca74648SRichard Henderson } 42061ca74648SRichard Henderson 42071ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 42081ca74648SRichard Henderson { 42091ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 42101ca74648SRichard Henderson } 42111ca74648SRichard Henderson 42121ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 42131ca74648SRichard Henderson { 42141ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 42151ca74648SRichard Henderson } 42161ca74648SRichard Henderson 42171ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 42181ca74648SRichard Henderson { 42191ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 42201ca74648SRichard Henderson } 42211ca74648SRichard Henderson 42221ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 42231ca74648SRichard Henderson { 42241ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 42251ca74648SRichard Henderson } 42261ca74648SRichard Henderson 42271ca74648SRichard Henderson /* 42281ca74648SRichard Henderson * Float class 2 42291ca74648SRichard Henderson */ 42301ca74648SRichard Henderson 42311ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4232ebe9383cSRichard Henderson { 4233ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4234ebe9383cSRichard Henderson 4235ebe9383cSRichard Henderson nullify_over(ctx); 4236ebe9383cSRichard Henderson 42371ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 42381ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 423929dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 424029dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4241ebe9383cSRichard Henderson 4242ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4243ebe9383cSRichard Henderson 42441ca74648SRichard Henderson return nullify_end(ctx); 4245ebe9383cSRichard Henderson } 4246ebe9383cSRichard Henderson 42471ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4248ebe9383cSRichard Henderson { 4249ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4250ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4251ebe9383cSRichard Henderson 4252ebe9383cSRichard Henderson nullify_over(ctx); 4253ebe9383cSRichard Henderson 42541ca74648SRichard Henderson ta = load_frd0(a->r1); 42551ca74648SRichard Henderson tb = load_frd0(a->r2); 425629dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 425729dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4258ebe9383cSRichard Henderson 4259ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4260ebe9383cSRichard Henderson 426131234768SRichard Henderson return nullify_end(ctx); 4262ebe9383cSRichard Henderson } 4263ebe9383cSRichard Henderson 42641ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4265ebe9383cSRichard Henderson { 42663692ad21SRichard Henderson TCGCond tc = TCG_COND_TSTNE; 42673692ad21SRichard Henderson uint32_t mask; 42686fd0c7bcSRichard Henderson TCGv_i64 t; 4269ebe9383cSRichard Henderson 4270ebe9383cSRichard Henderson nullify_over(ctx); 4271ebe9383cSRichard Henderson 4272aac0f603SRichard Henderson t = tcg_temp_new_i64(); 42736fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4274ebe9383cSRichard Henderson 42751ca74648SRichard Henderson if (a->y == 1) { 42761ca74648SRichard Henderson switch (a->c) { 4277ebe9383cSRichard Henderson case 0: /* simple */ 4278f33a22c1SRichard Henderson mask = R_FPSR_C_MASK; 4279f33a22c1SRichard Henderson break; 4280ebe9383cSRichard Henderson case 2: /* rej */ 42813692ad21SRichard Henderson tc = TCG_COND_TSTEQ; 4282ebe9383cSRichard Henderson /* fallthru */ 4283ebe9383cSRichard Henderson case 1: /* acc */ 4284f33a22c1SRichard Henderson mask = R_FPSR_C_MASK | R_FPSR_CQ_MASK; 4285ebe9383cSRichard Henderson break; 4286ebe9383cSRichard Henderson case 6: /* rej8 */ 42873692ad21SRichard Henderson tc = TCG_COND_TSTEQ; 4288ebe9383cSRichard Henderson /* fallthru */ 4289ebe9383cSRichard Henderson case 5: /* acc8 */ 4290f33a22c1SRichard Henderson mask = R_FPSR_C_MASK | R_FPSR_CQ0_6_MASK; 4291ebe9383cSRichard Henderson break; 4292ebe9383cSRichard Henderson case 9: /* acc6 */ 4293f33a22c1SRichard Henderson mask = R_FPSR_C_MASK | R_FPSR_CQ0_4_MASK; 4294ebe9383cSRichard Henderson break; 4295ebe9383cSRichard Henderson case 13: /* acc4 */ 4296f33a22c1SRichard Henderson mask = R_FPSR_C_MASK | R_FPSR_CQ0_2_MASK; 4297ebe9383cSRichard Henderson break; 4298ebe9383cSRichard Henderson case 17: /* acc2 */ 4299f33a22c1SRichard Henderson mask = R_FPSR_C_MASK | R_FPSR_CQ0_MASK; 4300ebe9383cSRichard Henderson break; 4301ebe9383cSRichard Henderson default: 43021ca74648SRichard Henderson gen_illegal(ctx); 43031ca74648SRichard Henderson return true; 4304ebe9383cSRichard Henderson } 43051ca74648SRichard Henderson } else { 43061ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 43073692ad21SRichard Henderson mask = R_FPSR_CA0_MASK >> cbit; 43081ca74648SRichard Henderson } 43091ca74648SRichard Henderson 43103692ad21SRichard Henderson ctx->null_cond = cond_make_ti(tc, t, mask); 431131234768SRichard Henderson return nullify_end(ctx); 4312ebe9383cSRichard Henderson } 4313ebe9383cSRichard Henderson 43141ca74648SRichard Henderson /* 43151ca74648SRichard Henderson * Float class 2 43161ca74648SRichard Henderson */ 43171ca74648SRichard Henderson 43181ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4319ebe9383cSRichard Henderson { 43201ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 43211ca74648SRichard Henderson } 43221ca74648SRichard Henderson 43231ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 43241ca74648SRichard Henderson { 43251ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 43261ca74648SRichard Henderson } 43271ca74648SRichard Henderson 43281ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 43291ca74648SRichard Henderson { 43301ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 43311ca74648SRichard Henderson } 43321ca74648SRichard Henderson 43331ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 43341ca74648SRichard Henderson { 43351ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 43361ca74648SRichard Henderson } 43371ca74648SRichard Henderson 43381ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 43391ca74648SRichard Henderson { 43401ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 43411ca74648SRichard Henderson } 43421ca74648SRichard Henderson 43431ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 43441ca74648SRichard Henderson { 43451ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 43461ca74648SRichard Henderson } 43471ca74648SRichard Henderson 43481ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 43491ca74648SRichard Henderson { 43501ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 43511ca74648SRichard Henderson } 43521ca74648SRichard Henderson 43531ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 43541ca74648SRichard Henderson { 43551ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 43561ca74648SRichard Henderson } 43571ca74648SRichard Henderson 43581ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 43591ca74648SRichard Henderson { 43601ca74648SRichard Henderson TCGv_i64 x, y; 4361ebe9383cSRichard Henderson 4362ebe9383cSRichard Henderson nullify_over(ctx); 4363ebe9383cSRichard Henderson 43641ca74648SRichard Henderson x = load_frw0_i64(a->r1); 43651ca74648SRichard Henderson y = load_frw0_i64(a->r2); 43661ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 43671ca74648SRichard Henderson save_frd(a->t, x); 4368ebe9383cSRichard Henderson 436931234768SRichard Henderson return nullify_end(ctx); 4370ebe9383cSRichard Henderson } 4371ebe9383cSRichard Henderson 4372ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4373ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4374ebe9383cSRichard Henderson { 4375ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4376ebe9383cSRichard Henderson } 4377ebe9383cSRichard Henderson 4378b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4379ebe9383cSRichard Henderson { 4380b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4381b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4382b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4383b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4384b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4385ebe9383cSRichard Henderson 4386ebe9383cSRichard Henderson nullify_over(ctx); 4387ebe9383cSRichard Henderson 4388ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4389ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4390ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4391ebe9383cSRichard Henderson 439231234768SRichard Henderson return nullify_end(ctx); 4393ebe9383cSRichard Henderson } 4394ebe9383cSRichard Henderson 4395b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4396b1e2af57SRichard Henderson { 4397b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4398b1e2af57SRichard Henderson } 4399b1e2af57SRichard Henderson 4400b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4401b1e2af57SRichard Henderson { 4402b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4403b1e2af57SRichard Henderson } 4404b1e2af57SRichard Henderson 4405b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4406b1e2af57SRichard Henderson { 4407b1e2af57SRichard Henderson nullify_over(ctx); 4408b1e2af57SRichard Henderson 4409b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4410b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4411b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4412b1e2af57SRichard Henderson 4413b1e2af57SRichard Henderson return nullify_end(ctx); 4414b1e2af57SRichard Henderson } 4415b1e2af57SRichard Henderson 4416b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4417b1e2af57SRichard Henderson { 4418b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4419b1e2af57SRichard Henderson } 4420b1e2af57SRichard Henderson 4421b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4422b1e2af57SRichard Henderson { 4423b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4424b1e2af57SRichard Henderson } 4425b1e2af57SRichard Henderson 4426c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4427ebe9383cSRichard Henderson { 4428c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4429ebe9383cSRichard Henderson 4430ebe9383cSRichard Henderson nullify_over(ctx); 4431c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4432c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4433c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4434ebe9383cSRichard Henderson 4435c3bad4f8SRichard Henderson if (a->neg) { 4436ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4437ebe9383cSRichard Henderson } else { 4438ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4439ebe9383cSRichard Henderson } 4440ebe9383cSRichard Henderson 4441c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 444231234768SRichard Henderson return nullify_end(ctx); 4443ebe9383cSRichard Henderson } 4444ebe9383cSRichard Henderson 4445c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4446ebe9383cSRichard Henderson { 4447c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4448ebe9383cSRichard Henderson 4449ebe9383cSRichard Henderson nullify_over(ctx); 4450c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4451c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4452c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4453ebe9383cSRichard Henderson 4454c3bad4f8SRichard Henderson if (a->neg) { 4455ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4456ebe9383cSRichard Henderson } else { 4457ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4458ebe9383cSRichard Henderson } 4459ebe9383cSRichard Henderson 4460c3bad4f8SRichard Henderson save_frd(a->t, x); 446131234768SRichard Henderson return nullify_end(ctx); 4462ebe9383cSRichard Henderson } 4463ebe9383cSRichard Henderson 446438193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */ 446538193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a) 446615da177bSSven Schnelle { 4467cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4468cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4469ad75a51eSRichard Henderson nullify_over(ctx); 4470ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4471cf6b28d4SHelge Deller return nullify_end(ctx); 447238193127SRichard Henderson #endif 447315da177bSSven Schnelle } 447438193127SRichard Henderson 447538193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */ 447638193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a) 447738193127SRichard Henderson { 447838193127SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 447938193127SRichard Henderson #ifndef CONFIG_USER_ONLY 4480dbca0835SHelge Deller nullify_over(ctx); 4481dbca0835SHelge Deller gen_helper_diag_console_output(tcg_env); 4482dbca0835SHelge Deller return nullify_end(ctx); 4483ad75a51eSRichard Henderson #endif 448438193127SRichard Henderson } 448538193127SRichard Henderson 44863bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a) 44873bdf2081SHelge Deller { 44883bdf2081SHelge Deller return !ctx->is_pa20 && do_getshadowregs(ctx); 44893bdf2081SHelge Deller } 44903bdf2081SHelge Deller 44913bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a) 44923bdf2081SHelge Deller { 44933bdf2081SHelge Deller return ctx->is_pa20 && do_getshadowregs(ctx); 44943bdf2081SHelge Deller } 44953bdf2081SHelge Deller 44963bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a) 44973bdf2081SHelge Deller { 44983bdf2081SHelge Deller return !ctx->is_pa20 && do_putshadowregs(ctx); 44993bdf2081SHelge Deller } 45003bdf2081SHelge Deller 45013bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a) 45023bdf2081SHelge Deller { 45033bdf2081SHelge Deller return ctx->is_pa20 && do_putshadowregs(ctx); 45043bdf2081SHelge Deller } 45053bdf2081SHelge Deller 450638193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a) 450738193127SRichard Henderson { 450838193127SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4509ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4510ad75a51eSRichard Henderson return true; 4511ad75a51eSRichard Henderson } 451215da177bSSven Schnelle 4513b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 451461766fe9SRichard Henderson { 451551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4516f764718dSRichard Henderson int bound; 451761766fe9SRichard Henderson 451851b061fbSRichard Henderson ctx->cs = cs; 4519494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4520bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 45213d68ee7bSRichard Henderson 45223d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4523c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 45243d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 45250d89cb7cSRichard Henderson ctx->iaoq_first = ctx->base.pc_first | ctx->privilege; 45260d89cb7cSRichard Henderson ctx->iaq_b.disp = ctx->base.tb->cs_base - ctx->base.pc_first; 4527217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4528c301f34eSRichard Henderson #else 4529494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4530bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4531bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4532451d993dSRichard Henderson : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX); 45333d68ee7bSRichard Henderson 4534c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4535c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4536c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4537c301f34eSRichard Henderson int32_t diff = cs_base; 4538c301f34eSRichard Henderson 45390d89cb7cSRichard Henderson ctx->iaoq_first = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 45400d89cb7cSRichard Henderson 4541bc921866SRichard Henderson if (diff) { 45420d89cb7cSRichard Henderson ctx->iaq_b.disp = diff; 4543bc921866SRichard Henderson } else { 4544bc921866SRichard Henderson ctx->iaq_b.base = cpu_iaoq_b; 4545bc921866SRichard Henderson ctx->iaq_b.space = cpu_iasq_b; 4546bc921866SRichard Henderson } 4547c301f34eSRichard Henderson #endif 454861766fe9SRichard Henderson 4549a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4550a4db4a78SRichard Henderson 45513d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 45523d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4553b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 455461766fe9SRichard Henderson } 455561766fe9SRichard Henderson 455651b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 455751b061fbSRichard Henderson { 455851b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 455961766fe9SRichard Henderson 45603d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 456151b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 456251b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4563494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 456451b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 456551b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4566129e9cc3SRichard Henderson } 456751b061fbSRichard Henderson ctx->null_lab = NULL; 456861766fe9SRichard Henderson } 456961766fe9SRichard Henderson 457051b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 457151b061fbSRichard Henderson { 457251b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 457351b061fbSRichard Henderson 4574bc921866SRichard Henderson tcg_debug_assert(!iaqe_variable(&ctx->iaq_f)); 45750d89cb7cSRichard Henderson tcg_gen_insn_start(ctx->iaoq_first + ctx->iaq_f.disp, 45760d89cb7cSRichard Henderson (iaqe_variable(&ctx->iaq_b) ? -1 : 45770d89cb7cSRichard Henderson ctx->iaoq_first + ctx->iaq_b.disp), 0); 457824638bd1SRichard Henderson ctx->insn_start_updated = false; 457951b061fbSRichard Henderson } 458051b061fbSRichard Henderson 458151b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 458251b061fbSRichard Henderson { 458351b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4584b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 458551b061fbSRichard Henderson DisasJumpType ret; 458651b061fbSRichard Henderson 458751b061fbSRichard Henderson /* Execute one insn. */ 4588ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4589c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 459031234768SRichard Henderson do_page_zero(ctx); 459131234768SRichard Henderson ret = ctx->base.is_jmp; 4592869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4593ba1d0b44SRichard Henderson } else 4594ba1d0b44SRichard Henderson #endif 4595ba1d0b44SRichard Henderson { 459661766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 459761766fe9SRichard Henderson the page permissions for execute. */ 45984e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 459961766fe9SRichard Henderson 4600bc921866SRichard Henderson /* 4601bc921866SRichard Henderson * Set up the IA queue for the next insn. 4602bc921866SRichard Henderson * This will be overwritten by a branch. 4603bc921866SRichard Henderson */ 4604bc921866SRichard Henderson ctx->iaq_n = NULL; 4605bc921866SRichard Henderson memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j)); 460661766fe9SRichard Henderson 460751b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 460851b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4609869051eaSRichard Henderson ret = DISAS_NEXT; 4610129e9cc3SRichard Henderson } else { 46111a19da0dSRichard Henderson ctx->insn = insn; 461231274b46SRichard Henderson if (!decode(ctx, insn)) { 461331274b46SRichard Henderson gen_illegal(ctx); 461431274b46SRichard Henderson } 461531234768SRichard Henderson ret = ctx->base.is_jmp; 461651b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4617129e9cc3SRichard Henderson } 461861766fe9SRichard Henderson } 461961766fe9SRichard Henderson 4620dbdccbdfSRichard Henderson /* If the TranslationBlock must end, do so. */ 4621dbdccbdfSRichard Henderson ctx->base.pc_next += 4; 4622dbdccbdfSRichard Henderson if (ret != DISAS_NEXT) { 4623dbdccbdfSRichard Henderson return; 462461766fe9SRichard Henderson } 4625dbdccbdfSRichard Henderson /* Note this also detects a priority change. */ 4626bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) 4627bc921866SRichard Henderson || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 4628dbdccbdfSRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 4629dbdccbdfSRichard Henderson return; 4630129e9cc3SRichard Henderson } 4631dbdccbdfSRichard Henderson 4632dbdccbdfSRichard Henderson /* 4633dbdccbdfSRichard Henderson * Advance the insn queue. 4634dbdccbdfSRichard Henderson * The only exit now is DISAS_TOO_MANY from the translator loop. 4635dbdccbdfSRichard Henderson */ 4636bc921866SRichard Henderson ctx->iaq_f.disp = ctx->iaq_b.disp; 4637bc921866SRichard Henderson if (!ctx->iaq_n) { 4638bc921866SRichard Henderson ctx->iaq_b.disp += 4; 4639bc921866SRichard Henderson return; 4640bc921866SRichard Henderson } 4641bc921866SRichard Henderson /* 4642bc921866SRichard Henderson * If IAQ_Next is variable in any way, we need to copy into the 4643bc921866SRichard Henderson * IAQ_Back globals, in case the next insn raises an exception. 4644bc921866SRichard Henderson */ 4645bc921866SRichard Henderson if (ctx->iaq_n->base) { 4646bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n); 4647bc921866SRichard Henderson ctx->iaq_b.base = cpu_iaoq_b; 4648bc921866SRichard Henderson ctx->iaq_b.disp = 0; 46490dcd6640SRichard Henderson } else { 4650bc921866SRichard Henderson ctx->iaq_b.disp = ctx->iaq_n->disp; 46510dcd6640SRichard Henderson } 4652bc921866SRichard Henderson if (ctx->iaq_n->space) { 4653bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space); 4654bc921866SRichard Henderson ctx->iaq_b.space = cpu_iasq_b; 4655142faf5fSRichard Henderson } 465661766fe9SRichard Henderson } 465761766fe9SRichard Henderson 465851b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 465951b061fbSRichard Henderson { 466051b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4661e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 4662dbdccbdfSRichard Henderson /* Assume the insn queue has not been advanced. */ 4663bc921866SRichard Henderson DisasIAQE *f = &ctx->iaq_b; 4664bc921866SRichard Henderson DisasIAQE *b = ctx->iaq_n; 466551b061fbSRichard Henderson 4666e1b5a5edSRichard Henderson switch (is_jmp) { 4667869051eaSRichard Henderson case DISAS_NORETURN: 466861766fe9SRichard Henderson break; 466951b061fbSRichard Henderson case DISAS_TOO_MANY: 4670dbdccbdfSRichard Henderson /* The insn queue has not been advanced. */ 4671bc921866SRichard Henderson f = &ctx->iaq_f; 4672bc921866SRichard Henderson b = &ctx->iaq_b; 467361766fe9SRichard Henderson /* FALLTHRU */ 4674dbdccbdfSRichard Henderson case DISAS_IAQ_N_STALE: 4675bc921866SRichard Henderson if (use_goto_tb(ctx, f, b) 4676dbdccbdfSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4677dbdccbdfSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 4678dbdccbdfSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 4679bc921866SRichard Henderson gen_goto_tb(ctx, 0, f, b); 46808532a14eSRichard Henderson break; 468161766fe9SRichard Henderson } 4682c5d0aec2SRichard Henderson /* FALLTHRU */ 4683dbdccbdfSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4684bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 4685dbdccbdfSRichard Henderson nullify_save(ctx); 4686dbdccbdfSRichard Henderson if (is_jmp == DISAS_IAQ_N_STALE_EXIT) { 4687dbdccbdfSRichard Henderson tcg_gen_exit_tb(NULL, 0); 4688dbdccbdfSRichard Henderson break; 4689dbdccbdfSRichard Henderson } 4690dbdccbdfSRichard Henderson /* FALLTHRU */ 4691dbdccbdfSRichard Henderson case DISAS_IAQ_N_UPDATED: 4692dbdccbdfSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 4693dbdccbdfSRichard Henderson break; 4694c5d0aec2SRichard Henderson case DISAS_EXIT: 4695c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 469661766fe9SRichard Henderson break; 469761766fe9SRichard Henderson default: 469851b061fbSRichard Henderson g_assert_not_reached(); 469961766fe9SRichard Henderson } 470051b061fbSRichard Henderson } 470161766fe9SRichard Henderson 47028eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 47038eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 470451b061fbSRichard Henderson { 4705c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 470661766fe9SRichard Henderson 4707ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4708ba1d0b44SRichard Henderson switch (pc) { 47097ad439dfSRichard Henderson case 0x00: 47108eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4711ba1d0b44SRichard Henderson return; 47127ad439dfSRichard Henderson case 0xb0: 47138eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4714ba1d0b44SRichard Henderson return; 47157ad439dfSRichard Henderson case 0xe0: 47168eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4717ba1d0b44SRichard Henderson return; 47187ad439dfSRichard Henderson case 0x100: 47198eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4720ba1d0b44SRichard Henderson return; 47217ad439dfSRichard Henderson } 4722ba1d0b44SRichard Henderson #endif 4723ba1d0b44SRichard Henderson 47248eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 47258eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 472661766fe9SRichard Henderson } 472751b061fbSRichard Henderson 472851b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 472951b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 473051b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 473151b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 473251b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 473351b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 473451b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 473551b061fbSRichard Henderson }; 473651b061fbSRichard Henderson 4737597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 473832f0c394SAnton Johansson vaddr pc, void *host_pc) 473951b061fbSRichard Henderson { 4740bc921866SRichard Henderson DisasContext ctx = { }; 4741306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 474261766fe9SRichard Henderson } 4743