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 45*bc921866SRichard Henderson typedef struct DisasIAQE { 46*bc921866SRichard Henderson /* IASQ; may be null for no change from TB. */ 47*bc921866SRichard Henderson TCGv_i64 space; 48*bc921866SRichard Henderson /* IAOQ base; may be null for immediate absolute address. */ 49*bc921866SRichard Henderson TCGv_i64 base; 50*bc921866SRichard Henderson /* IAOQ addend; absolute immedate address if base is null. */ 51*bc921866SRichard Henderson int64_t disp; 52*bc921866SRichard Henderson } DisasIAQE; 53*bc921866SRichard Henderson 5461766fe9SRichard Henderson typedef struct DisasContext { 55d01a3625SRichard Henderson DisasContextBase base; 5661766fe9SRichard Henderson CPUState *cs; 5761766fe9SRichard Henderson 58*bc921866SRichard Henderson /* IAQ_Front, IAQ_Back. */ 59*bc921866SRichard Henderson DisasIAQE iaq_f, iaq_b; 60*bc921866SRichard Henderson /* IAQ_Next, for jumps, otherwise null for simple advance. */ 61*bc921866SRichard Henderson DisasIAQE iaq_j, *iaq_n; 6261766fe9SRichard Henderson 6361766fe9SRichard Henderson DisasCond null_cond; 6461766fe9SRichard Henderson TCGLabel *null_lab; 6561766fe9SRichard Henderson 66a4db4a78SRichard Henderson TCGv_i64 zero; 67a4db4a78SRichard Henderson 681a19da0dSRichard Henderson uint32_t insn; 69494737b7SRichard Henderson uint32_t tb_flags; 703d68ee7bSRichard Henderson int mmu_idx; 713d68ee7bSRichard Henderson int privilege; 7261766fe9SRichard Henderson bool psw_n_nonzero; 73bd6243a3SRichard Henderson bool is_pa20; 7424638bd1SRichard Henderson bool insn_start_updated; 75217d1a5eSRichard Henderson 76217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 77217d1a5eSRichard Henderson MemOp unalign; 78217d1a5eSRichard Henderson #endif 7961766fe9SRichard Henderson } DisasContext; 8061766fe9SRichard Henderson 81217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 82217d1a5eSRichard Henderson #define UNALIGN(C) (C)->unalign 8317fe594cSRichard Henderson #define MMU_DISABLED(C) false 84217d1a5eSRichard Henderson #else 852d4afb03SRichard Henderson #define UNALIGN(C) MO_ALIGN 8617fe594cSRichard Henderson #define MMU_DISABLED(C) MMU_IDX_MMU_DISABLED((C)->mmu_idx) 87217d1a5eSRichard Henderson #endif 88217d1a5eSRichard Henderson 89e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 90451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val) 91e36f27efSRichard Henderson { 92881d1073SHelge Deller /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */ 93881d1073SHelge Deller if (ctx->is_pa20) { 94e36f27efSRichard Henderson if (val & PSW_SM_W) { 95881d1073SHelge Deller val |= PSW_W; 96881d1073SHelge Deller } 97881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_G); 98881d1073SHelge Deller } else { 99881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_O); 100e36f27efSRichard Henderson } 101e36f27efSRichard Henderson return val; 102e36f27efSRichard Henderson } 103e36f27efSRichard Henderson 104deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base. */ 105451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val) 106deee69a1SRichard Henderson { 107deee69a1SRichard Henderson return ~val; 108deee69a1SRichard Henderson } 109deee69a1SRichard Henderson 1101cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value 1111cd012a5SRichard Henderson we use for the final M. */ 112451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val) 1131cd012a5SRichard Henderson { 1141cd012a5SRichard Henderson return val & 2 ? (val & 1 ? -1 : 1) : 0; 1151cd012a5SRichard Henderson } 1161cd012a5SRichard Henderson 117740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify. */ 118451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val) 119740038d7SRichard Henderson { 120740038d7SRichard Henderson return val ? 1 : -1; 121740038d7SRichard Henderson } 122740038d7SRichard Henderson 123451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val) 124740038d7SRichard Henderson { 125740038d7SRichard Henderson return val ? -1 : 1; 126740038d7SRichard Henderson } 127740038d7SRichard Henderson 128740038d7SRichard Henderson /* Used for branch targets and fp memory ops. */ 129451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val) 13001afb7beSRichard Henderson { 13101afb7beSRichard Henderson return val << 2; 13201afb7beSRichard Henderson } 13301afb7beSRichard Henderson 1340588e061SRichard Henderson /* Used for assemble_21. */ 135451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val) 1360588e061SRichard Henderson { 1370588e061SRichard Henderson return val << 11; 1380588e061SRichard Henderson } 1390588e061SRichard Henderson 14072ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val) 14172ae4f2bSRichard Henderson { 14272ae4f2bSRichard Henderson /* 14372ae4f2bSRichard Henderson * Officially, 32 * x + 32 - y. 14472ae4f2bSRichard Henderson * Here, x is already in bit 5, and y is [4:0]. 14572ae4f2bSRichard Henderson * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1, 14672ae4f2bSRichard Henderson * with the overflow from bit 4 summing with x. 14772ae4f2bSRichard Henderson */ 14872ae4f2bSRichard Henderson return (val ^ 31) + 1; 14972ae4f2bSRichard Henderson } 15072ae4f2bSRichard Henderson 1514768c28eSRichard Henderson /* Expander for assemble_16a(s,cat(im10a,0),i). */ 1524768c28eSRichard Henderson static int expand_11a(DisasContext *ctx, int val) 1534768c28eSRichard Henderson { 1544768c28eSRichard Henderson /* 1554768c28eSRichard Henderson * @val is bit 0 and bits [4:15]. 1564768c28eSRichard Henderson * Swizzle thing around depending on PSW.W. 1574768c28eSRichard Henderson */ 1584768c28eSRichard Henderson int im10a = extract32(val, 1, 10); 1594768c28eSRichard Henderson int s = extract32(val, 11, 2); 1604768c28eSRichard Henderson int i = (-(val & 1) << 13) | (im10a << 3); 1614768c28eSRichard Henderson 1624768c28eSRichard Henderson if (ctx->tb_flags & PSW_W) { 1634768c28eSRichard Henderson i ^= s << 13; 1644768c28eSRichard Henderson } 1654768c28eSRichard Henderson return i; 1664768c28eSRichard Henderson } 1674768c28eSRichard Henderson 16846174e14SRichard Henderson /* Expander for assemble_16a(s,im11a,i). */ 16946174e14SRichard Henderson static int expand_12a(DisasContext *ctx, int val) 17046174e14SRichard Henderson { 17146174e14SRichard Henderson /* 17246174e14SRichard Henderson * @val is bit 0 and bits [3:15]. 17346174e14SRichard Henderson * Swizzle thing around depending on PSW.W. 17446174e14SRichard Henderson */ 17546174e14SRichard Henderson int im11a = extract32(val, 1, 11); 17646174e14SRichard Henderson int s = extract32(val, 12, 2); 17746174e14SRichard Henderson int i = (-(val & 1) << 13) | (im11a << 2); 17846174e14SRichard Henderson 17946174e14SRichard Henderson if (ctx->tb_flags & PSW_W) { 18046174e14SRichard Henderson i ^= s << 13; 18146174e14SRichard Henderson } 18246174e14SRichard Henderson return i; 18346174e14SRichard Henderson } 18446174e14SRichard Henderson 18572bace2dSRichard Henderson /* Expander for assemble_16(s,im14). */ 18672bace2dSRichard Henderson static int expand_16(DisasContext *ctx, int val) 18772bace2dSRichard Henderson { 18872bace2dSRichard Henderson /* 18972bace2dSRichard Henderson * @val is bits [0:15], containing both im14 and s. 19072bace2dSRichard Henderson * Swizzle thing around depending on PSW.W. 19172bace2dSRichard Henderson */ 19272bace2dSRichard Henderson int s = extract32(val, 14, 2); 19372bace2dSRichard Henderson int i = (-(val & 1) << 13) | extract32(val, 1, 13); 19472bace2dSRichard Henderson 19572bace2dSRichard Henderson if (ctx->tb_flags & PSW_W) { 19672bace2dSRichard Henderson i ^= s << 13; 19772bace2dSRichard Henderson } 19872bace2dSRichard Henderson return i; 19972bace2dSRichard Henderson } 20072bace2dSRichard Henderson 20172bace2dSRichard Henderson /* The sp field is only present with !PSW_W. */ 20272bace2dSRichard Henderson static int sp0_if_wide(DisasContext *ctx, int sp) 20372bace2dSRichard Henderson { 20472bace2dSRichard Henderson return ctx->tb_flags & PSW_W ? 0 : sp; 20572bace2dSRichard Henderson } 20672bace2dSRichard Henderson 207c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */ 208c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val) 209c65c3ee1SRichard Henderson { 210c65c3ee1SRichard Henderson return val ? val : 4; /* 0 == "*<<" */ 211c65c3ee1SRichard Henderson } 212c65c3ee1SRichard Henderson 21382d0c831SRichard Henderson /* 21482d0c831SRichard Henderson * In many places pa1.x did not decode the bit that later became 21582d0c831SRichard Henderson * the pa2.0 D bit. Suppress D unless the cpu is pa2.0. 21682d0c831SRichard Henderson */ 21782d0c831SRichard Henderson static int pa20_d(DisasContext *ctx, int val) 21882d0c831SRichard Henderson { 21982d0c831SRichard Henderson return ctx->is_pa20 & val; 22082d0c831SRichard Henderson } 22101afb7beSRichard Henderson 22240f9f908SRichard Henderson /* Include the auto-generated decoder. */ 223abff1abfSPaolo Bonzini #include "decode-insns.c.inc" 22440f9f908SRichard Henderson 22561766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 22661766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 227869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 22861766fe9SRichard Henderson 22961766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 23061766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 231869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 23261766fe9SRichard Henderson 233e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 234e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 235e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 236c5d0aec2SRichard Henderson #define DISAS_EXIT DISAS_TARGET_3 237e1b5a5edSRichard Henderson 23861766fe9SRichard Henderson /* global register indexes */ 2396fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32]; 24033423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 241494737b7SRichard Henderson static TCGv_i64 cpu_srH; 2426fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f; 2436fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b; 244c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 245c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 2466fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar; 2476fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n; 2486fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v; 2496fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb; 2506fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb; 25161766fe9SRichard Henderson 25261766fe9SRichard Henderson void hppa_translate_init(void) 25361766fe9SRichard Henderson { 25461766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 25561766fe9SRichard Henderson 2566fd0c7bcSRichard Henderson typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 25761766fe9SRichard Henderson static const GlobalVar vars[] = { 25835136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 25961766fe9SRichard Henderson DEF_VAR(psw_n), 26061766fe9SRichard Henderson DEF_VAR(psw_v), 26161766fe9SRichard Henderson DEF_VAR(psw_cb), 26261766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 26361766fe9SRichard Henderson DEF_VAR(iaoq_f), 26461766fe9SRichard Henderson DEF_VAR(iaoq_b), 26561766fe9SRichard Henderson }; 26661766fe9SRichard Henderson 26761766fe9SRichard Henderson #undef DEF_VAR 26861766fe9SRichard Henderson 26961766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 27061766fe9SRichard Henderson static const char gr_names[32][4] = { 27161766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 27261766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 27361766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 27461766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 27561766fe9SRichard Henderson }; 27633423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 277494737b7SRichard Henderson static const char sr_names[5][4] = { 278494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 27933423472SRichard Henderson }; 28061766fe9SRichard Henderson 28161766fe9SRichard Henderson int i; 28261766fe9SRichard Henderson 283f764718dSRichard Henderson cpu_gr[0] = NULL; 28461766fe9SRichard Henderson for (i = 1; i < 32; i++) { 285ad75a51eSRichard Henderson cpu_gr[i] = tcg_global_mem_new(tcg_env, 28661766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 28761766fe9SRichard Henderson gr_names[i]); 28861766fe9SRichard Henderson } 28933423472SRichard Henderson for (i = 0; i < 4; i++) { 290ad75a51eSRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 29133423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 29233423472SRichard Henderson sr_names[i]); 29333423472SRichard Henderson } 294ad75a51eSRichard Henderson cpu_srH = tcg_global_mem_new_i64(tcg_env, 295494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 296494737b7SRichard Henderson sr_names[4]); 29761766fe9SRichard Henderson 29861766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 29961766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 300ad75a51eSRichard Henderson *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 30161766fe9SRichard Henderson } 302c301f34eSRichard Henderson 303ad75a51eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 304c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 305c301f34eSRichard Henderson "iasq_f"); 306ad75a51eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 307c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 308c301f34eSRichard Henderson "iasq_b"); 30961766fe9SRichard Henderson } 31061766fe9SRichard Henderson 311f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg) 312f5b5c857SRichard Henderson { 31324638bd1SRichard Henderson assert(!ctx->insn_start_updated); 31424638bd1SRichard Henderson ctx->insn_start_updated = true; 31524638bd1SRichard Henderson tcg_set_insn_start_param(ctx->base.insn_start, 2, breg); 316f5b5c857SRichard Henderson } 317f5b5c857SRichard Henderson 318129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 319129e9cc3SRichard Henderson { 320f764718dSRichard Henderson return (DisasCond){ 321f764718dSRichard Henderson .c = TCG_COND_NEVER, 322f764718dSRichard Henderson .a0 = NULL, 323f764718dSRichard Henderson .a1 = NULL, 324f764718dSRichard Henderson }; 325129e9cc3SRichard Henderson } 326129e9cc3SRichard Henderson 327df0232feSRichard Henderson static DisasCond cond_make_t(void) 328df0232feSRichard Henderson { 329df0232feSRichard Henderson return (DisasCond){ 330df0232feSRichard Henderson .c = TCG_COND_ALWAYS, 331df0232feSRichard Henderson .a0 = NULL, 332df0232feSRichard Henderson .a1 = NULL, 333df0232feSRichard Henderson }; 334df0232feSRichard Henderson } 335df0232feSRichard Henderson 336129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 337129e9cc3SRichard Henderson { 338f764718dSRichard Henderson return (DisasCond){ 339f764718dSRichard Henderson .c = TCG_COND_NE, 340f764718dSRichard Henderson .a0 = cpu_psw_n, 3416fd0c7bcSRichard Henderson .a1 = tcg_constant_i64(0) 342f764718dSRichard Henderson }; 343129e9cc3SRichard Henderson } 344129e9cc3SRichard Henderson 3456fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 346b47a4a02SSven Schnelle { 347b47a4a02SSven Schnelle assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 3484fe9533aSRichard Henderson return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 3494fe9533aSRichard Henderson } 3504fe9533aSRichard Henderson 3516fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0) 3524fe9533aSRichard Henderson { 3536fd0c7bcSRichard Henderson return cond_make_tmp(c, a0, tcg_constant_i64(0)); 354b47a4a02SSven Schnelle } 355b47a4a02SSven Schnelle 3566fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0) 357129e9cc3SRichard Henderson { 358aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3596fd0c7bcSRichard Henderson tcg_gen_mov_i64(tmp, a0); 360b47a4a02SSven Schnelle return cond_make_0_tmp(c, tmp); 361129e9cc3SRichard Henderson } 362129e9cc3SRichard Henderson 3636fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 364129e9cc3SRichard Henderson { 365aac0f603SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 366aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 367129e9cc3SRichard Henderson 3686fd0c7bcSRichard Henderson tcg_gen_mov_i64(t0, a0); 3696fd0c7bcSRichard Henderson tcg_gen_mov_i64(t1, a1); 3704fe9533aSRichard Henderson return cond_make_tmp(c, t0, t1); 371129e9cc3SRichard Henderson } 372129e9cc3SRichard Henderson 373129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 374129e9cc3SRichard Henderson { 375129e9cc3SRichard Henderson switch (cond->c) { 376129e9cc3SRichard Henderson default: 377f764718dSRichard Henderson cond->a0 = NULL; 378f764718dSRichard Henderson cond->a1 = NULL; 379129e9cc3SRichard Henderson /* fallthru */ 380129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 381129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 382129e9cc3SRichard Henderson break; 383129e9cc3SRichard Henderson case TCG_COND_NEVER: 384129e9cc3SRichard Henderson break; 385129e9cc3SRichard Henderson } 386129e9cc3SRichard Henderson } 387129e9cc3SRichard Henderson 3886fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 38961766fe9SRichard Henderson { 39061766fe9SRichard Henderson if (reg == 0) { 391bc3da3cfSRichard Henderson return ctx->zero; 39261766fe9SRichard Henderson } else { 39361766fe9SRichard Henderson return cpu_gr[reg]; 39461766fe9SRichard Henderson } 39561766fe9SRichard Henderson } 39661766fe9SRichard Henderson 3976fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 39861766fe9SRichard Henderson { 399129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 400aac0f603SRichard Henderson return tcg_temp_new_i64(); 40161766fe9SRichard Henderson } else { 40261766fe9SRichard Henderson return cpu_gr[reg]; 40361766fe9SRichard Henderson } 40461766fe9SRichard Henderson } 40561766fe9SRichard Henderson 4066fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 407129e9cc3SRichard Henderson { 408129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 4096fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 410129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 411129e9cc3SRichard Henderson } else { 4126fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 413129e9cc3SRichard Henderson } 414129e9cc3SRichard Henderson } 415129e9cc3SRichard Henderson 4166fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 417129e9cc3SRichard Henderson { 418129e9cc3SRichard Henderson if (reg != 0) { 419129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 420129e9cc3SRichard Henderson } 421129e9cc3SRichard Henderson } 422129e9cc3SRichard Henderson 423e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 42496d6407fSRichard Henderson # define HI_OFS 0 42596d6407fSRichard Henderson # define LO_OFS 4 42696d6407fSRichard Henderson #else 42796d6407fSRichard Henderson # define HI_OFS 4 42896d6407fSRichard Henderson # define LO_OFS 0 42996d6407fSRichard Henderson #endif 43096d6407fSRichard Henderson 43196d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 43296d6407fSRichard Henderson { 43396d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 434ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 43596d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 43696d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 43796d6407fSRichard Henderson return ret; 43896d6407fSRichard Henderson } 43996d6407fSRichard Henderson 440ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 441ebe9383cSRichard Henderson { 442ebe9383cSRichard Henderson if (rt == 0) { 4430992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 4440992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 4450992a930SRichard Henderson return ret; 446ebe9383cSRichard Henderson } else { 447ebe9383cSRichard Henderson return load_frw_i32(rt); 448ebe9383cSRichard Henderson } 449ebe9383cSRichard Henderson } 450ebe9383cSRichard Henderson 451ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 452ebe9383cSRichard Henderson { 453ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4540992a930SRichard Henderson if (rt == 0) { 4550992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4560992a930SRichard Henderson } else { 457ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 458ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 459ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 460ebe9383cSRichard Henderson } 4610992a930SRichard Henderson return ret; 462ebe9383cSRichard Henderson } 463ebe9383cSRichard Henderson 46496d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 46596d6407fSRichard Henderson { 466ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 46796d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 46896d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 46996d6407fSRichard Henderson } 47096d6407fSRichard Henderson 47196d6407fSRichard Henderson #undef HI_OFS 47296d6407fSRichard Henderson #undef LO_OFS 47396d6407fSRichard Henderson 47496d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 47596d6407fSRichard Henderson { 47696d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 477ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 47896d6407fSRichard Henderson return ret; 47996d6407fSRichard Henderson } 48096d6407fSRichard Henderson 481ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 482ebe9383cSRichard Henderson { 483ebe9383cSRichard Henderson if (rt == 0) { 4840992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4850992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4860992a930SRichard Henderson return ret; 487ebe9383cSRichard Henderson } else { 488ebe9383cSRichard Henderson return load_frd(rt); 489ebe9383cSRichard Henderson } 490ebe9383cSRichard Henderson } 491ebe9383cSRichard Henderson 49296d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 49396d6407fSRichard Henderson { 494ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 49596d6407fSRichard Henderson } 49696d6407fSRichard Henderson 49733423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 49833423472SRichard Henderson { 49933423472SRichard Henderson #ifdef CONFIG_USER_ONLY 50033423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 50133423472SRichard Henderson #else 50233423472SRichard Henderson if (reg < 4) { 50333423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 504494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 505494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 50633423472SRichard Henderson } else { 507ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 50833423472SRichard Henderson } 50933423472SRichard Henderson #endif 51033423472SRichard Henderson } 51133423472SRichard Henderson 512129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 513129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 514129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 515129e9cc3SRichard Henderson { 516129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 517129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 518129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 519129e9cc3SRichard Henderson 520129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 521129e9cc3SRichard Henderson 522129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 5236e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 524aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 5256fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 526129e9cc3SRichard Henderson } 527129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 528129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 529129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 530129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 531129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 5326fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 533129e9cc3SRichard Henderson } 534129e9cc3SRichard Henderson 5356fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 536129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 537129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 538129e9cc3SRichard Henderson } 539129e9cc3SRichard Henderson } 540129e9cc3SRichard Henderson 541129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 542129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 543129e9cc3SRichard Henderson { 544129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 545129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 5466fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 547129e9cc3SRichard Henderson } 548129e9cc3SRichard Henderson return; 549129e9cc3SRichard Henderson } 5506e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 5516fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 552129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 553129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 554129e9cc3SRichard Henderson } 555129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 556129e9cc3SRichard Henderson } 557129e9cc3SRichard Henderson 558129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 559129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 560129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 561129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 562129e9cc3SRichard Henderson { 563129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 5646fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 565129e9cc3SRichard Henderson } 566129e9cc3SRichard Henderson } 567129e9cc3SRichard Henderson 568129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 56940f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 57040f9f908SRichard Henderson it may be tail-called from a translate function. */ 57131234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 572129e9cc3SRichard Henderson { 573129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 57431234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 575129e9cc3SRichard Henderson 576f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 577f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 578f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 579f49b3537SRichard Henderson 580129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 581129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 582129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 583129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 58431234768SRichard Henderson return true; 585129e9cc3SRichard Henderson } 586129e9cc3SRichard Henderson ctx->null_lab = NULL; 587129e9cc3SRichard Henderson 588129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 589129e9cc3SRichard Henderson /* The next instruction will be unconditional, 590129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 591129e9cc3SRichard Henderson gen_set_label(null_lab); 592129e9cc3SRichard Henderson } else { 593129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 594129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 595129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 596129e9cc3SRichard Henderson label we have the proper value in place. */ 597129e9cc3SRichard Henderson nullify_save(ctx); 598129e9cc3SRichard Henderson gen_set_label(null_lab); 599129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 600129e9cc3SRichard Henderson } 601869051eaSRichard Henderson if (status == DISAS_NORETURN) { 60231234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 603129e9cc3SRichard Henderson } 60431234768SRichard Henderson return true; 605129e9cc3SRichard Henderson } 606129e9cc3SRichard Henderson 607*bc921866SRichard Henderson static bool iaqe_variable(const DisasIAQE *e) 608*bc921866SRichard Henderson { 609*bc921866SRichard Henderson return e->base || e->space; 610*bc921866SRichard Henderson } 611*bc921866SRichard Henderson 612*bc921866SRichard Henderson static DisasIAQE iaqe_incr(const DisasIAQE *e, int64_t disp) 613*bc921866SRichard Henderson { 614*bc921866SRichard Henderson return (DisasIAQE){ 615*bc921866SRichard Henderson .space = e->space, 616*bc921866SRichard Henderson .base = e->base, 617*bc921866SRichard Henderson .disp = e->disp + disp, 618*bc921866SRichard Henderson }; 619*bc921866SRichard Henderson } 620*bc921866SRichard Henderson 621*bc921866SRichard Henderson static DisasIAQE iaqe_branchi(DisasContext *ctx, int64_t disp) 622*bc921866SRichard Henderson { 623*bc921866SRichard Henderson return (DisasIAQE){ 624*bc921866SRichard Henderson .space = ctx->iaq_b.space, 625*bc921866SRichard Henderson .disp = ctx->iaq_f.disp + 8 + disp, 626*bc921866SRichard Henderson }; 627*bc921866SRichard Henderson } 628*bc921866SRichard Henderson 629*bc921866SRichard Henderson static DisasIAQE iaqe_next_absv(DisasContext *ctx, TCGv_i64 var) 630*bc921866SRichard Henderson { 631*bc921866SRichard Henderson return (DisasIAQE){ 632*bc921866SRichard Henderson .space = ctx->iaq_b.space, 633*bc921866SRichard Henderson .base = var, 634*bc921866SRichard Henderson }; 635*bc921866SRichard Henderson } 636*bc921866SRichard Henderson 6376fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 638*bc921866SRichard Henderson const DisasIAQE *src) 63961766fe9SRichard Henderson { 6407d50b696SSven Schnelle uint64_t mask = gva_offset_mask(ctx->tb_flags); 641f13bf343SRichard Henderson 642*bc921866SRichard Henderson if (src->base == NULL) { 643*bc921866SRichard Henderson tcg_gen_movi_i64(dest, src->disp & mask); 644*bc921866SRichard Henderson } else if (src->disp == 0) { 645*bc921866SRichard Henderson tcg_gen_andi_i64(dest, src->base, mask); 64661766fe9SRichard Henderson } else { 647*bc921866SRichard Henderson tcg_gen_addi_i64(dest, src->base, src->disp); 648*bc921866SRichard Henderson tcg_gen_andi_i64(dest, dest, mask); 64961766fe9SRichard Henderson } 65061766fe9SRichard Henderson } 65161766fe9SRichard Henderson 652*bc921866SRichard Henderson static void install_iaq_entries(DisasContext *ctx, const DisasIAQE *f, 653*bc921866SRichard Henderson const DisasIAQE *b) 65485e6cda0SRichard Henderson { 655*bc921866SRichard Henderson DisasIAQE b_next; 65685e6cda0SRichard Henderson 657*bc921866SRichard Henderson if (b == NULL) { 658*bc921866SRichard Henderson b_next = iaqe_incr(f, 4); 659*bc921866SRichard Henderson b = &b_next; 66085e6cda0SRichard Henderson } 661*bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f); 662*bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b); 663*bc921866SRichard Henderson if (f->space) { 664*bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, f->space); 665588deedaSRichard Henderson } 666*bc921866SRichard Henderson if (b->space || f->space) { 667*bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, b->space ? : f->space); 668588deedaSRichard Henderson } 66985e6cda0SRichard Henderson } 67085e6cda0SRichard Henderson 67143541db0SRichard Henderson static void install_link(DisasContext *ctx, unsigned link, bool with_sr0) 67243541db0SRichard Henderson { 67343541db0SRichard Henderson tcg_debug_assert(ctx->null_cond.c == TCG_COND_NEVER); 67443541db0SRichard Henderson if (!link) { 67543541db0SRichard Henderson return; 67643541db0SRichard Henderson } 677*bc921866SRichard Henderson if (ctx->iaq_b.base) { 678*bc921866SRichard Henderson tcg_gen_addi_i64(cpu_gr[link], ctx->iaq_b.base, 679*bc921866SRichard Henderson ctx->iaq_b.disp + 4); 68043541db0SRichard Henderson } else { 681*bc921866SRichard Henderson tcg_gen_movi_i64(cpu_gr[link], ctx->iaq_b.disp + 4); 68243541db0SRichard Henderson } 68343541db0SRichard Henderson #ifndef CONFIG_USER_ONLY 68443541db0SRichard Henderson if (with_sr0) { 68543541db0SRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_b); 68643541db0SRichard Henderson } 68743541db0SRichard Henderson #endif 68843541db0SRichard Henderson } 68943541db0SRichard Henderson 69061766fe9SRichard Henderson static void gen_excp_1(int exception) 69161766fe9SRichard Henderson { 692ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 69361766fe9SRichard Henderson } 69461766fe9SRichard Henderson 69531234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 69661766fe9SRichard Henderson { 697*bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_f, &ctx->iaq_b); 698129e9cc3SRichard Henderson nullify_save(ctx); 69961766fe9SRichard Henderson gen_excp_1(exception); 70031234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 70161766fe9SRichard Henderson } 70261766fe9SRichard Henderson 70331234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 7041a19da0dSRichard Henderson { 70531234768SRichard Henderson nullify_over(ctx); 7066fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 707ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 70831234768SRichard Henderson gen_excp(ctx, exc); 70931234768SRichard Henderson return nullify_end(ctx); 7101a19da0dSRichard Henderson } 7111a19da0dSRichard Henderson 71231234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 71361766fe9SRichard Henderson { 71431234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 71561766fe9SRichard Henderson } 71661766fe9SRichard Henderson 71740f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 71840f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 71940f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 72040f9f908SRichard Henderson #else 721e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 722e1b5a5edSRichard Henderson do { \ 723e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 72431234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 725e1b5a5edSRichard Henderson } \ 726e1b5a5edSRichard Henderson } while (0) 72740f9f908SRichard Henderson #endif 728e1b5a5edSRichard Henderson 729*bc921866SRichard Henderson static bool use_goto_tb(DisasContext *ctx, const DisasIAQE *f, 730*bc921866SRichard Henderson const DisasIAQE *b) 73161766fe9SRichard Henderson { 732*bc921866SRichard Henderson return (!iaqe_variable(f) && 733*bc921866SRichard Henderson (b == NULL || !iaqe_variable(b)) && 734*bc921866SRichard Henderson translator_use_goto_tb(&ctx->base, f->disp)); 73561766fe9SRichard Henderson } 73661766fe9SRichard Henderson 737129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 738129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 739129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 740129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 741129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 742129e9cc3SRichard Henderson { 743f9b11bc2SRichard Henderson return (!(tb_cflags(ctx->base.tb) & CF_BP_PAGE) 744*bc921866SRichard Henderson && !iaqe_variable(&ctx->iaq_b) 745*bc921866SRichard Henderson && is_same_page(&ctx->base, ctx->iaq_b.disp)); 746129e9cc3SRichard Henderson } 747129e9cc3SRichard Henderson 74861766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 749*bc921866SRichard Henderson const DisasIAQE *f, const DisasIAQE *b) 75061766fe9SRichard Henderson { 751*bc921866SRichard Henderson if (use_goto_tb(ctx, f, b)) { 75261766fe9SRichard Henderson tcg_gen_goto_tb(which); 753*bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 75407ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 75561766fe9SRichard Henderson } else { 756*bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 7577f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 75861766fe9SRichard Henderson } 75961766fe9SRichard Henderson } 76061766fe9SRichard Henderson 761b47a4a02SSven Schnelle static bool cond_need_sv(int c) 762b47a4a02SSven Schnelle { 763b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 764b47a4a02SSven Schnelle } 765b47a4a02SSven Schnelle 766b47a4a02SSven Schnelle static bool cond_need_cb(int c) 767b47a4a02SSven Schnelle { 768b47a4a02SSven Schnelle return c == 4 || c == 5; 769b47a4a02SSven Schnelle } 770b47a4a02SSven Schnelle 771b47a4a02SSven Schnelle /* 772b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 773b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 774b47a4a02SSven Schnelle */ 775b2167459SRichard Henderson 776a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 777fe2d066aSRichard Henderson TCGv_i64 res, TCGv_i64 uv, TCGv_i64 sv) 778b2167459SRichard Henderson { 779b2167459SRichard Henderson DisasCond cond; 7806fd0c7bcSRichard Henderson TCGv_i64 tmp; 781b2167459SRichard Henderson 782b2167459SRichard Henderson switch (cf >> 1) { 783b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 784b2167459SRichard Henderson cond = cond_make_f(); 785b2167459SRichard Henderson break; 786b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 78782d0c831SRichard Henderson if (!d) { 788aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7896fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 790a751eb31SRichard Henderson res = tmp; 791a751eb31SRichard Henderson } 792b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 793b2167459SRichard Henderson break; 794b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 795aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7966fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 79782d0c831SRichard Henderson if (!d) { 7986fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, tmp); 799a751eb31SRichard Henderson } 800b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_LT, tmp); 801b2167459SRichard Henderson break; 802b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 803b47a4a02SSven Schnelle /* 804b47a4a02SSven Schnelle * Simplify: 805b47a4a02SSven Schnelle * (N ^ V) | Z 806b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 807b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 808b47a4a02SSven Schnelle * (~(res ^ sv) >= 0) | !res 809b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31) | !res 810b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31 & res) 811b47a4a02SSven Schnelle */ 812aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 8136fd0c7bcSRichard Henderson tcg_gen_eqv_i64(tmp, res, sv); 81482d0c831SRichard Henderson if (!d) { 8156fd0c7bcSRichard Henderson tcg_gen_sextract_i64(tmp, tmp, 31, 1); 8166fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 8176fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 818a751eb31SRichard Henderson } else { 8196fd0c7bcSRichard Henderson tcg_gen_sari_i64(tmp, tmp, 63); 8206fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 821a751eb31SRichard Henderson } 822b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 823b2167459SRichard Henderson break; 824fe2d066aSRichard Henderson case 4: /* NUV / UV (!UV / UV) */ 825fe2d066aSRichard Henderson cond = cond_make_0(TCG_COND_EQ, uv); 826b2167459SRichard Henderson break; 827fe2d066aSRichard Henderson case 5: /* ZNV / VNZ (!UV | Z / UV & !Z) */ 828aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 829fe2d066aSRichard Henderson tcg_gen_movcond_i64(TCG_COND_EQ, tmp, uv, ctx->zero, ctx->zero, res); 83082d0c831SRichard Henderson if (!d) { 8316fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 832a751eb31SRichard Henderson } 833b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 834b2167459SRichard Henderson break; 835b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 83682d0c831SRichard Henderson if (!d) { 837aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 8386fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, sv); 839a751eb31SRichard Henderson sv = tmp; 840a751eb31SRichard Henderson } 841b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 842b2167459SRichard Henderson break; 843b2167459SRichard Henderson case 7: /* OD / EV */ 844aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 8456fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, res, 1); 846b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_NE, tmp); 847b2167459SRichard Henderson break; 848b2167459SRichard Henderson default: 849b2167459SRichard Henderson g_assert_not_reached(); 850b2167459SRichard Henderson } 851b2167459SRichard Henderson if (cf & 1) { 852b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 853b2167459SRichard Henderson } 854b2167459SRichard Henderson 855b2167459SRichard Henderson return cond; 856b2167459SRichard Henderson } 857b2167459SRichard Henderson 858b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 859b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 860b2167459SRichard Henderson deleted as unused. */ 861b2167459SRichard Henderson 8624fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 8636fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 8646fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 865b2167459SRichard Henderson { 8664fe9533aSRichard Henderson TCGCond tc; 8674fe9533aSRichard Henderson bool ext_uns; 868b2167459SRichard Henderson 869b2167459SRichard Henderson switch (cf >> 1) { 870b2167459SRichard Henderson case 1: /* = / <> */ 8714fe9533aSRichard Henderson tc = TCG_COND_EQ; 8724fe9533aSRichard Henderson ext_uns = true; 873b2167459SRichard Henderson break; 874b2167459SRichard Henderson case 2: /* < / >= */ 8754fe9533aSRichard Henderson tc = TCG_COND_LT; 8764fe9533aSRichard Henderson ext_uns = false; 877b2167459SRichard Henderson break; 878b2167459SRichard Henderson case 3: /* <= / > */ 8794fe9533aSRichard Henderson tc = TCG_COND_LE; 8804fe9533aSRichard Henderson ext_uns = false; 881b2167459SRichard Henderson break; 882b2167459SRichard Henderson case 4: /* << / >>= */ 8834fe9533aSRichard Henderson tc = TCG_COND_LTU; 8844fe9533aSRichard Henderson ext_uns = true; 885b2167459SRichard Henderson break; 886b2167459SRichard Henderson case 5: /* <<= / >> */ 8874fe9533aSRichard Henderson tc = TCG_COND_LEU; 8884fe9533aSRichard Henderson ext_uns = true; 889b2167459SRichard Henderson break; 890b2167459SRichard Henderson default: 891a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 892b2167459SRichard Henderson } 893b2167459SRichard Henderson 8944fe9533aSRichard Henderson if (cf & 1) { 8954fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 8964fe9533aSRichard Henderson } 89782d0c831SRichard Henderson if (!d) { 898aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 899aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 9004fe9533aSRichard Henderson 9014fe9533aSRichard Henderson if (ext_uns) { 9026fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 9036fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 9044fe9533aSRichard Henderson } else { 9056fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 9066fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 9074fe9533aSRichard Henderson } 9084fe9533aSRichard Henderson return cond_make_tmp(tc, t1, t2); 9094fe9533aSRichard Henderson } 9104fe9533aSRichard Henderson return cond_make(tc, in1, in2); 911b2167459SRichard Henderson } 912b2167459SRichard Henderson 913df0232feSRichard Henderson /* 914df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 915df0232feSRichard Henderson * computed, and use of them is undefined. 916df0232feSRichard Henderson * 917df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 918df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 919df0232feSRichard Henderson * how cases c={2,3} are treated. 920df0232feSRichard Henderson */ 921b2167459SRichard Henderson 922b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 9236fd0c7bcSRichard Henderson TCGv_i64 res) 924b2167459SRichard Henderson { 925b5af8423SRichard Henderson TCGCond tc; 926b5af8423SRichard Henderson bool ext_uns; 927a751eb31SRichard Henderson 928df0232feSRichard Henderson switch (cf) { 929df0232feSRichard Henderson case 0: /* never */ 930df0232feSRichard Henderson case 9: /* undef, C */ 931df0232feSRichard Henderson case 11: /* undef, C & !Z */ 932df0232feSRichard Henderson case 12: /* undef, V */ 933df0232feSRichard Henderson return cond_make_f(); 934df0232feSRichard Henderson 935df0232feSRichard Henderson case 1: /* true */ 936df0232feSRichard Henderson case 8: /* undef, !C */ 937df0232feSRichard Henderson case 10: /* undef, !C | Z */ 938df0232feSRichard Henderson case 13: /* undef, !V */ 939df0232feSRichard Henderson return cond_make_t(); 940df0232feSRichard Henderson 941df0232feSRichard Henderson case 2: /* == */ 942b5af8423SRichard Henderson tc = TCG_COND_EQ; 943b5af8423SRichard Henderson ext_uns = true; 944b5af8423SRichard Henderson break; 945df0232feSRichard Henderson case 3: /* <> */ 946b5af8423SRichard Henderson tc = TCG_COND_NE; 947b5af8423SRichard Henderson ext_uns = true; 948b5af8423SRichard Henderson break; 949df0232feSRichard Henderson case 4: /* < */ 950b5af8423SRichard Henderson tc = TCG_COND_LT; 951b5af8423SRichard Henderson ext_uns = false; 952b5af8423SRichard Henderson break; 953df0232feSRichard Henderson case 5: /* >= */ 954b5af8423SRichard Henderson tc = TCG_COND_GE; 955b5af8423SRichard Henderson ext_uns = false; 956b5af8423SRichard Henderson break; 957df0232feSRichard Henderson case 6: /* <= */ 958b5af8423SRichard Henderson tc = TCG_COND_LE; 959b5af8423SRichard Henderson ext_uns = false; 960b5af8423SRichard Henderson break; 961df0232feSRichard Henderson case 7: /* > */ 962b5af8423SRichard Henderson tc = TCG_COND_GT; 963b5af8423SRichard Henderson ext_uns = false; 964b5af8423SRichard Henderson break; 965df0232feSRichard Henderson 966df0232feSRichard Henderson case 14: /* OD */ 967df0232feSRichard Henderson case 15: /* EV */ 968a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, NULL); 969df0232feSRichard Henderson 970df0232feSRichard Henderson default: 971df0232feSRichard Henderson g_assert_not_reached(); 972b2167459SRichard Henderson } 973b5af8423SRichard Henderson 97482d0c831SRichard Henderson if (!d) { 975aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 976b5af8423SRichard Henderson 977b5af8423SRichard Henderson if (ext_uns) { 9786fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 979b5af8423SRichard Henderson } else { 9806fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 981b5af8423SRichard Henderson } 982b5af8423SRichard Henderson return cond_make_0_tmp(tc, tmp); 983b5af8423SRichard Henderson } 984b5af8423SRichard Henderson return cond_make_0(tc, res); 985b2167459SRichard Henderson } 986b2167459SRichard Henderson 98798cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 98898cd9ca7SRichard Henderson 9894fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 9906fd0c7bcSRichard Henderson TCGv_i64 res) 99198cd9ca7SRichard Henderson { 99298cd9ca7SRichard Henderson unsigned c, f; 99398cd9ca7SRichard Henderson 99498cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 99598cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 99698cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 99798cd9ca7SRichard Henderson c = orig & 3; 99898cd9ca7SRichard Henderson if (c == 3) { 99998cd9ca7SRichard Henderson c = 7; 100098cd9ca7SRichard Henderson } 100198cd9ca7SRichard Henderson f = (orig & 4) / 4; 100298cd9ca7SRichard Henderson 1003b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 100498cd9ca7SRichard Henderson } 100598cd9ca7SRichard Henderson 100646bb3d46SRichard Henderson /* Similar, but for unit zero conditions. */ 100746bb3d46SRichard Henderson static DisasCond do_unit_zero_cond(unsigned cf, bool d, TCGv_i64 res) 1008b2167459SRichard Henderson { 100946bb3d46SRichard Henderson TCGv_i64 tmp; 1010c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 101146bb3d46SRichard Henderson uint64_t ones = 0, sgns = 0; 1012b2167459SRichard Henderson 1013b2167459SRichard Henderson switch (cf >> 1) { 1014578b8132SSven Schnelle case 1: /* SBW / NBW */ 1015578b8132SSven Schnelle if (d) { 101646bb3d46SRichard Henderson ones = d_repl; 101746bb3d46SRichard Henderson sgns = d_repl << 31; 1018578b8132SSven Schnelle } 1019578b8132SSven Schnelle break; 1020b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 102146bb3d46SRichard Henderson ones = d_repl * 0x01010101u; 102246bb3d46SRichard Henderson sgns = ones << 7; 102346bb3d46SRichard Henderson break; 102446bb3d46SRichard Henderson case 3: /* SHZ / NHZ */ 102546bb3d46SRichard Henderson ones = d_repl * 0x00010001u; 102646bb3d46SRichard Henderson sgns = ones << 15; 102746bb3d46SRichard Henderson break; 102846bb3d46SRichard Henderson } 102946bb3d46SRichard Henderson if (ones == 0) { 103046bb3d46SRichard Henderson /* Undefined, or 0/1 (never/always). */ 103146bb3d46SRichard Henderson return cf & 1 ? cond_make_t() : cond_make_f(); 103246bb3d46SRichard Henderson } 103346bb3d46SRichard Henderson 103446bb3d46SRichard Henderson /* 103546bb3d46SRichard Henderson * See hasless(v,1) from 1036b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 1037b2167459SRichard Henderson */ 1038aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 103946bb3d46SRichard Henderson tcg_gen_subi_i64(tmp, res, ones); 10406fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 104146bb3d46SRichard Henderson tcg_gen_andi_i64(tmp, tmp, sgns); 1042b2167459SRichard Henderson 104346bb3d46SRichard Henderson return cond_make_0_tmp(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, tmp); 1044b2167459SRichard Henderson } 1045b2167459SRichard Henderson 10466fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 10476fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 104872ca8753SRichard Henderson { 104982d0c831SRichard Henderson if (!d) { 1050aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 10516fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 105272ca8753SRichard Henderson return t; 105372ca8753SRichard Henderson } 105472ca8753SRichard Henderson return cb_msb; 105572ca8753SRichard Henderson } 105672ca8753SRichard Henderson 10576fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 105872ca8753SRichard Henderson { 105972ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 106072ca8753SRichard Henderson } 106172ca8753SRichard Henderson 1062b2167459SRichard Henderson /* Compute signed overflow for addition. */ 10636fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 1064f8f5986eSRichard Henderson TCGv_i64 in1, TCGv_i64 in2, 1065f8f5986eSRichard Henderson TCGv_i64 orig_in1, int shift, bool d) 1066b2167459SRichard Henderson { 1067aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1068aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1069b2167459SRichard Henderson 10706fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10716fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10726fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 1073b2167459SRichard Henderson 1074f8f5986eSRichard Henderson switch (shift) { 1075f8f5986eSRichard Henderson case 0: 1076f8f5986eSRichard Henderson break; 1077f8f5986eSRichard Henderson case 1: 1078f8f5986eSRichard Henderson /* Shift left by one and compare the sign. */ 1079f8f5986eSRichard Henderson tcg_gen_add_i64(tmp, orig_in1, orig_in1); 1080f8f5986eSRichard Henderson tcg_gen_xor_i64(tmp, tmp, orig_in1); 1081f8f5986eSRichard Henderson /* Incorporate into the overflow. */ 1082f8f5986eSRichard Henderson tcg_gen_or_i64(sv, sv, tmp); 1083f8f5986eSRichard Henderson break; 1084f8f5986eSRichard Henderson default: 1085f8f5986eSRichard Henderson { 1086f8f5986eSRichard Henderson int sign_bit = d ? 63 : 31; 1087f8f5986eSRichard Henderson 1088f8f5986eSRichard Henderson /* Compare the sign against all lower bits. */ 1089f8f5986eSRichard Henderson tcg_gen_sextract_i64(tmp, orig_in1, sign_bit, 1); 1090f8f5986eSRichard Henderson tcg_gen_xor_i64(tmp, tmp, orig_in1); 1091f8f5986eSRichard Henderson /* 1092f8f5986eSRichard Henderson * If one of the bits shifting into or through the sign 1093f8f5986eSRichard Henderson * differs, then we have overflow. 1094f8f5986eSRichard Henderson */ 1095f8f5986eSRichard Henderson tcg_gen_extract_i64(tmp, tmp, sign_bit - shift, shift); 1096f8f5986eSRichard Henderson tcg_gen_movcond_i64(TCG_COND_NE, sv, tmp, ctx->zero, 1097f8f5986eSRichard Henderson tcg_constant_i64(-1), sv); 1098f8f5986eSRichard Henderson } 1099f8f5986eSRichard Henderson } 1100b2167459SRichard Henderson return sv; 1101b2167459SRichard Henderson } 1102b2167459SRichard Henderson 1103f8f5986eSRichard Henderson /* Compute unsigned overflow for addition. */ 1104f8f5986eSRichard Henderson static TCGv_i64 do_add_uv(DisasContext *ctx, TCGv_i64 cb, TCGv_i64 cb_msb, 1105f8f5986eSRichard Henderson TCGv_i64 in1, int shift, bool d) 1106f8f5986eSRichard Henderson { 1107f8f5986eSRichard Henderson if (shift == 0) { 1108f8f5986eSRichard Henderson return get_carry(ctx, d, cb, cb_msb); 1109f8f5986eSRichard Henderson } else { 1110f8f5986eSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1111f8f5986eSRichard Henderson tcg_gen_extract_i64(tmp, in1, (d ? 63 : 31) - shift, shift); 1112f8f5986eSRichard Henderson tcg_gen_or_i64(tmp, tmp, get_carry(ctx, d, cb, cb_msb)); 1113f8f5986eSRichard Henderson return tmp; 1114f8f5986eSRichard Henderson } 1115f8f5986eSRichard Henderson } 1116f8f5986eSRichard Henderson 1117b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 11186fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 11196fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1120b2167459SRichard Henderson { 1121aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1122aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1123b2167459SRichard Henderson 11246fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 11256fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 11266fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 1127b2167459SRichard Henderson 1128b2167459SRichard Henderson return sv; 1129b2167459SRichard Henderson } 1130b2167459SRichard Henderson 1131f8f5986eSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1, 11326fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1133faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1134b2167459SRichard Henderson { 1135f8f5986eSRichard Henderson TCGv_i64 dest, cb, cb_msb, in1, uv, sv, tmp; 1136b2167459SRichard Henderson unsigned c = cf >> 1; 1137b2167459SRichard Henderson DisasCond cond; 1138b2167459SRichard Henderson 1139aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1140f764718dSRichard Henderson cb = NULL; 1141f764718dSRichard Henderson cb_msb = NULL; 1142b2167459SRichard Henderson 1143f8f5986eSRichard Henderson in1 = orig_in1; 1144b2167459SRichard Henderson if (shift) { 1145aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11466fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1147b2167459SRichard Henderson in1 = tmp; 1148b2167459SRichard Henderson } 1149b2167459SRichard Henderson 1150b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1151aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1152aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1153bdcccc17SRichard Henderson 1154a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1155b2167459SRichard Henderson if (is_c) { 11566fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1157a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1158b2167459SRichard Henderson } 11596fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 11606fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1161b2167459SRichard Henderson } else { 11626fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1163b2167459SRichard Henderson if (is_c) { 11646fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1165b2167459SRichard Henderson } 1166b2167459SRichard Henderson } 1167b2167459SRichard Henderson 1168b2167459SRichard Henderson /* Compute signed overflow if required. */ 1169f764718dSRichard Henderson sv = NULL; 1170b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1171f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, in1, in2, orig_in1, shift, d); 1172b2167459SRichard Henderson if (is_tsv) { 1173bd1ad92cSSven Schnelle if (!d) { 1174bd1ad92cSSven Schnelle tcg_gen_ext32s_i64(sv, sv); 1175bd1ad92cSSven Schnelle } 1176ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1177b2167459SRichard Henderson } 1178b2167459SRichard Henderson } 1179b2167459SRichard Henderson 1180f8f5986eSRichard Henderson /* Compute unsigned overflow if required. */ 1181f8f5986eSRichard Henderson uv = NULL; 1182f8f5986eSRichard Henderson if (cond_need_cb(c)) { 1183f8f5986eSRichard Henderson uv = do_add_uv(ctx, cb, cb_msb, orig_in1, shift, d); 1184f8f5986eSRichard Henderson } 1185f8f5986eSRichard Henderson 1186b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1187f8f5986eSRichard Henderson cond = do_cond(ctx, cf, d, dest, uv, sv); 1188b2167459SRichard Henderson if (is_tc) { 1189aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11906fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1191ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1192b2167459SRichard Henderson } 1193b2167459SRichard Henderson 1194b2167459SRichard Henderson /* Write back the result. */ 1195b2167459SRichard Henderson if (!is_l) { 1196b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1197b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1198b2167459SRichard Henderson } 1199b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1200b2167459SRichard Henderson 1201b2167459SRichard Henderson /* Install the new nullification. */ 1202b2167459SRichard Henderson cond_free(&ctx->null_cond); 1203b2167459SRichard Henderson ctx->null_cond = cond; 1204b2167459SRichard Henderson } 1205b2167459SRichard Henderson 1206faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 12070c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 12080c982a28SRichard Henderson { 12096fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12100c982a28SRichard Henderson 12110c982a28SRichard Henderson if (a->cf) { 12120c982a28SRichard Henderson nullify_over(ctx); 12130c982a28SRichard Henderson } 12140c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12150c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1216faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1217faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 12180c982a28SRichard Henderson return nullify_end(ctx); 12190c982a28SRichard Henderson } 12200c982a28SRichard Henderson 12210588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 12220588e061SRichard Henderson bool is_tsv, bool is_tc) 12230588e061SRichard Henderson { 12246fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 12250588e061SRichard Henderson 12260588e061SRichard Henderson if (a->cf) { 12270588e061SRichard Henderson nullify_over(ctx); 12280588e061SRichard Henderson } 12296fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 12300588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1231faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1232faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 12330588e061SRichard Henderson return nullify_end(ctx); 12340588e061SRichard Henderson } 12350588e061SRichard Henderson 12366fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12376fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 123863c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1239b2167459SRichard Henderson { 1240a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1241b2167459SRichard Henderson unsigned c = cf >> 1; 1242b2167459SRichard Henderson DisasCond cond; 1243b2167459SRichard Henderson 1244aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1245aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1246aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1247b2167459SRichard Henderson 1248b2167459SRichard Henderson if (is_b) { 1249b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 12506fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1251a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1252a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1253a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 12546fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 12556fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1256b2167459SRichard Henderson } else { 1257bdcccc17SRichard Henderson /* 1258bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1259bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1260bdcccc17SRichard Henderson */ 12616fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1262a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 12636fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 12646fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1265b2167459SRichard Henderson } 1266b2167459SRichard Henderson 1267b2167459SRichard Henderson /* Compute signed overflow if required. */ 1268f764718dSRichard Henderson sv = NULL; 1269b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1270b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1271b2167459SRichard Henderson if (is_tsv) { 1272bd1ad92cSSven Schnelle if (!d) { 1273bd1ad92cSSven Schnelle tcg_gen_ext32s_i64(sv, sv); 1274bd1ad92cSSven Schnelle } 1275ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1276b2167459SRichard Henderson } 1277b2167459SRichard Henderson } 1278b2167459SRichard Henderson 1279b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1280b2167459SRichard Henderson if (!is_b) { 12814fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1282b2167459SRichard Henderson } else { 1283a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1284b2167459SRichard Henderson } 1285b2167459SRichard Henderson 1286b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1287b2167459SRichard Henderson if (is_tc) { 1288aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 12896fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1290ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1291b2167459SRichard Henderson } 1292b2167459SRichard Henderson 1293b2167459SRichard Henderson /* Write back the result. */ 1294b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1295b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1296b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1297b2167459SRichard Henderson 1298b2167459SRichard Henderson /* Install the new nullification. */ 1299b2167459SRichard Henderson cond_free(&ctx->null_cond); 1300b2167459SRichard Henderson ctx->null_cond = cond; 1301b2167459SRichard Henderson } 1302b2167459SRichard Henderson 130363c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 13040c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 13050c982a28SRichard Henderson { 13066fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 13070c982a28SRichard Henderson 13080c982a28SRichard Henderson if (a->cf) { 13090c982a28SRichard Henderson nullify_over(ctx); 13100c982a28SRichard Henderson } 13110c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 13120c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 131363c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 13140c982a28SRichard Henderson return nullify_end(ctx); 13150c982a28SRichard Henderson } 13160c982a28SRichard Henderson 13170588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 13180588e061SRichard Henderson { 13196fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 13200588e061SRichard Henderson 13210588e061SRichard Henderson if (a->cf) { 13220588e061SRichard Henderson nullify_over(ctx); 13230588e061SRichard Henderson } 13246fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 13250588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 132663c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 132763c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 13280588e061SRichard Henderson return nullify_end(ctx); 13290588e061SRichard Henderson } 13300588e061SRichard Henderson 13316fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 13326fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1333b2167459SRichard Henderson { 13346fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1335b2167459SRichard Henderson DisasCond cond; 1336b2167459SRichard Henderson 1337aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 13386fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1339b2167459SRichard Henderson 1340b2167459SRichard Henderson /* Compute signed overflow if required. */ 1341f764718dSRichard Henderson sv = NULL; 1342b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1343b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1344b2167459SRichard Henderson } 1345b2167459SRichard Henderson 1346b2167459SRichard Henderson /* Form the condition for the compare. */ 13474fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1348b2167459SRichard Henderson 1349b2167459SRichard Henderson /* Clear. */ 13506fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1351b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1352b2167459SRichard Henderson 1353b2167459SRichard Henderson /* Install the new nullification. */ 1354b2167459SRichard Henderson cond_free(&ctx->null_cond); 1355b2167459SRichard Henderson ctx->null_cond = cond; 1356b2167459SRichard Henderson } 1357b2167459SRichard Henderson 13586fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 13596fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 13606fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1361b2167459SRichard Henderson { 13626fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1363b2167459SRichard Henderson 1364b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1365b2167459SRichard Henderson fn(dest, in1, in2); 1366b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1367b2167459SRichard Henderson 1368b2167459SRichard Henderson /* Install the new nullification. */ 1369b2167459SRichard Henderson cond_free(&ctx->null_cond); 1370b2167459SRichard Henderson if (cf) { 1371b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1372b2167459SRichard Henderson } 1373b2167459SRichard Henderson } 1374b2167459SRichard Henderson 1375fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 13766fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 13770c982a28SRichard Henderson { 13786fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 13790c982a28SRichard Henderson 13800c982a28SRichard Henderson if (a->cf) { 13810c982a28SRichard Henderson nullify_over(ctx); 13820c982a28SRichard Henderson } 13830c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 13840c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1385fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 13860c982a28SRichard Henderson return nullify_end(ctx); 13870c982a28SRichard Henderson } 13880c982a28SRichard Henderson 138946bb3d46SRichard Henderson static void do_unit_addsub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 139046bb3d46SRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 139146bb3d46SRichard Henderson bool is_tc, bool is_add) 1392b2167459SRichard Henderson { 139346bb3d46SRichard Henderson TCGv_i64 dest = tcg_temp_new_i64(); 139446bb3d46SRichard Henderson uint64_t test_cb = 0; 1395b2167459SRichard Henderson DisasCond cond; 1396b2167459SRichard Henderson 139746bb3d46SRichard Henderson /* Select which carry-out bits to test. */ 139846bb3d46SRichard Henderson switch (cf >> 1) { 139946bb3d46SRichard Henderson case 4: /* NDC / SDC -- 4-bit carries */ 140046bb3d46SRichard Henderson test_cb = dup_const(MO_8, 0x88); 140146bb3d46SRichard Henderson break; 140246bb3d46SRichard Henderson case 5: /* NWC / SWC -- 32-bit carries */ 140346bb3d46SRichard Henderson if (d) { 140446bb3d46SRichard Henderson test_cb = dup_const(MO_32, INT32_MIN); 1405b2167459SRichard Henderson } else { 140646bb3d46SRichard Henderson cf &= 1; /* undefined -- map to never/always */ 140746bb3d46SRichard Henderson } 140846bb3d46SRichard Henderson break; 140946bb3d46SRichard Henderson case 6: /* NBC / SBC -- 8-bit carries */ 141046bb3d46SRichard Henderson test_cb = dup_const(MO_8, INT8_MIN); 141146bb3d46SRichard Henderson break; 141246bb3d46SRichard Henderson case 7: /* NHC / SHC -- 16-bit carries */ 141346bb3d46SRichard Henderson test_cb = dup_const(MO_16, INT16_MIN); 141446bb3d46SRichard Henderson break; 141546bb3d46SRichard Henderson } 141646bb3d46SRichard Henderson if (!d) { 141746bb3d46SRichard Henderson test_cb = (uint32_t)test_cb; 141846bb3d46SRichard Henderson } 1419b2167459SRichard Henderson 142046bb3d46SRichard Henderson if (!test_cb) { 142146bb3d46SRichard Henderson /* No need to compute carries if we don't need to test them. */ 142246bb3d46SRichard Henderson if (is_add) { 142346bb3d46SRichard Henderson tcg_gen_add_i64(dest, in1, in2); 142446bb3d46SRichard Henderson } else { 142546bb3d46SRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 142646bb3d46SRichard Henderson } 142746bb3d46SRichard Henderson cond = do_unit_zero_cond(cf, d, dest); 142846bb3d46SRichard Henderson } else { 142946bb3d46SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 143046bb3d46SRichard Henderson 143146bb3d46SRichard Henderson if (d) { 143246bb3d46SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 143346bb3d46SRichard Henderson if (is_add) { 143446bb3d46SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 143546bb3d46SRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 143646bb3d46SRichard Henderson } else { 143746bb3d46SRichard Henderson /* See do_sub, !is_b. */ 143846bb3d46SRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 143946bb3d46SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 144046bb3d46SRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 144146bb3d46SRichard Henderson } 144246bb3d46SRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 144346bb3d46SRichard Henderson tcg_gen_extract2_i64(cb, cb, cb_msb, 1); 144446bb3d46SRichard Henderson } else { 144546bb3d46SRichard Henderson if (is_add) { 144646bb3d46SRichard Henderson tcg_gen_add_i64(dest, in1, in2); 144746bb3d46SRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 144846bb3d46SRichard Henderson } else { 144946bb3d46SRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 145046bb3d46SRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 145146bb3d46SRichard Henderson } 145246bb3d46SRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 145346bb3d46SRichard Henderson tcg_gen_shri_i64(cb, cb, 1); 145446bb3d46SRichard Henderson } 145546bb3d46SRichard Henderson 145646bb3d46SRichard Henderson tcg_gen_andi_i64(cb, cb, test_cb); 145746bb3d46SRichard Henderson cond = cond_make_0_tmp(cf & 1 ? TCG_COND_EQ : TCG_COND_NE, cb); 145846bb3d46SRichard Henderson } 1459b2167459SRichard Henderson 1460b2167459SRichard Henderson if (is_tc) { 1461aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 14626fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1463ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1464b2167459SRichard Henderson } 1465b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1466b2167459SRichard Henderson 1467b2167459SRichard Henderson cond_free(&ctx->null_cond); 1468b2167459SRichard Henderson ctx->null_cond = cond; 1469b2167459SRichard Henderson } 1470b2167459SRichard Henderson 147186f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 14728d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 14738d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 14748d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 14758d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 14766fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 147786f8d05fSRichard Henderson { 147886f8d05fSRichard Henderson TCGv_ptr ptr; 14796fd0c7bcSRichard Henderson TCGv_i64 tmp; 148086f8d05fSRichard Henderson TCGv_i64 spc; 148186f8d05fSRichard Henderson 148286f8d05fSRichard Henderson if (sp != 0) { 14838d6ae7fbSRichard Henderson if (sp < 0) { 14848d6ae7fbSRichard Henderson sp = ~sp; 14858d6ae7fbSRichard Henderson } 14866fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 14878d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 14888d6ae7fbSRichard Henderson return spc; 148986f8d05fSRichard Henderson } 1490494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1491494737b7SRichard Henderson return cpu_srH; 1492494737b7SRichard Henderson } 149386f8d05fSRichard Henderson 149486f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1495aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 14966fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 149786f8d05fSRichard Henderson 1498698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 14996fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 15006fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 15016fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 150286f8d05fSRichard Henderson 1503ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 150486f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 150586f8d05fSRichard Henderson 150686f8d05fSRichard Henderson return spc; 150786f8d05fSRichard Henderson } 150886f8d05fSRichard Henderson #endif 150986f8d05fSRichard Henderson 15106fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1511c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 151286f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 151386f8d05fSRichard Henderson { 15146fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 15156fd0c7bcSRichard Henderson TCGv_i64 ofs; 15166fd0c7bcSRichard Henderson TCGv_i64 addr; 151786f8d05fSRichard Henderson 1518f5b5c857SRichard Henderson set_insn_breg(ctx, rb); 1519f5b5c857SRichard Henderson 152086f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 152186f8d05fSRichard Henderson if (rx) { 1522aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 15236fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 15246fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 152586f8d05fSRichard Henderson } else if (disp || modify) { 1526aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 15276fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 152886f8d05fSRichard Henderson } else { 152986f8d05fSRichard Henderson ofs = base; 153086f8d05fSRichard Henderson } 153186f8d05fSRichard Henderson 153286f8d05fSRichard Henderson *pofs = ofs; 15336fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 15347d50b696SSven Schnelle tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, 15357d50b696SSven Schnelle gva_offset_mask(ctx->tb_flags)); 1536698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 153786f8d05fSRichard Henderson if (!is_phys) { 1538d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 153986f8d05fSRichard Henderson } 154086f8d05fSRichard Henderson #endif 154186f8d05fSRichard Henderson } 154286f8d05fSRichard Henderson 154396d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 154496d6407fSRichard Henderson * < 0 for pre-modify, 154596d6407fSRichard Henderson * > 0 for post-modify, 154696d6407fSRichard Henderson * = 0 for no base register update. 154796d6407fSRichard Henderson */ 154896d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1549c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 155014776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 155196d6407fSRichard Henderson { 15526fd0c7bcSRichard Henderson TCGv_i64 ofs; 15536fd0c7bcSRichard Henderson TCGv_i64 addr; 155496d6407fSRichard Henderson 155596d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 155696d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 155796d6407fSRichard Henderson 155886f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 155917fe594cSRichard Henderson MMU_DISABLED(ctx)); 1560c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 156186f8d05fSRichard Henderson if (modify) { 156286f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 156396d6407fSRichard Henderson } 156496d6407fSRichard Henderson } 156596d6407fSRichard Henderson 156696d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1567c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 156814776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 156996d6407fSRichard Henderson { 15706fd0c7bcSRichard Henderson TCGv_i64 ofs; 15716fd0c7bcSRichard Henderson TCGv_i64 addr; 157296d6407fSRichard Henderson 157396d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 157496d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 157596d6407fSRichard Henderson 157686f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 157717fe594cSRichard Henderson MMU_DISABLED(ctx)); 1578217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 157986f8d05fSRichard Henderson if (modify) { 158086f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 158196d6407fSRichard Henderson } 158296d6407fSRichard Henderson } 158396d6407fSRichard Henderson 158496d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1585c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 158614776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 158796d6407fSRichard Henderson { 15886fd0c7bcSRichard Henderson TCGv_i64 ofs; 15896fd0c7bcSRichard Henderson TCGv_i64 addr; 159096d6407fSRichard Henderson 159196d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 159296d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 159396d6407fSRichard Henderson 159486f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 159517fe594cSRichard Henderson MMU_DISABLED(ctx)); 1596217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 159786f8d05fSRichard Henderson if (modify) { 159886f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 159996d6407fSRichard Henderson } 160096d6407fSRichard Henderson } 160196d6407fSRichard Henderson 160296d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1603c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 160414776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 160596d6407fSRichard Henderson { 16066fd0c7bcSRichard Henderson TCGv_i64 ofs; 16076fd0c7bcSRichard Henderson TCGv_i64 addr; 160896d6407fSRichard Henderson 160996d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 161096d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 161196d6407fSRichard Henderson 161286f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 161317fe594cSRichard Henderson MMU_DISABLED(ctx)); 1614217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 161586f8d05fSRichard Henderson if (modify) { 161686f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 161796d6407fSRichard Henderson } 161896d6407fSRichard Henderson } 161996d6407fSRichard Henderson 16201cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1621c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 162214776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 162396d6407fSRichard Henderson { 16246fd0c7bcSRichard Henderson TCGv_i64 dest; 162596d6407fSRichard Henderson 162696d6407fSRichard Henderson nullify_over(ctx); 162796d6407fSRichard Henderson 162896d6407fSRichard Henderson if (modify == 0) { 162996d6407fSRichard Henderson /* No base register update. */ 163096d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 163196d6407fSRichard Henderson } else { 163296d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1633aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 163496d6407fSRichard Henderson } 16356fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 163696d6407fSRichard Henderson save_gpr(ctx, rt, dest); 163796d6407fSRichard Henderson 16381cd012a5SRichard Henderson return nullify_end(ctx); 163996d6407fSRichard Henderson } 164096d6407fSRichard Henderson 1641740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1642c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 164386f8d05fSRichard Henderson unsigned sp, int modify) 164496d6407fSRichard Henderson { 164596d6407fSRichard Henderson TCGv_i32 tmp; 164696d6407fSRichard Henderson 164796d6407fSRichard Henderson nullify_over(ctx); 164896d6407fSRichard Henderson 164996d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 165086f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 165196d6407fSRichard Henderson save_frw_i32(rt, tmp); 165296d6407fSRichard Henderson 165396d6407fSRichard Henderson if (rt == 0) { 1654ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 165596d6407fSRichard Henderson } 165696d6407fSRichard Henderson 1657740038d7SRichard Henderson return nullify_end(ctx); 165896d6407fSRichard Henderson } 165996d6407fSRichard Henderson 1660740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1661740038d7SRichard Henderson { 1662740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1663740038d7SRichard Henderson a->disp, a->sp, a->m); 1664740038d7SRichard Henderson } 1665740038d7SRichard Henderson 1666740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1667c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 166886f8d05fSRichard Henderson unsigned sp, int modify) 166996d6407fSRichard Henderson { 167096d6407fSRichard Henderson TCGv_i64 tmp; 167196d6407fSRichard Henderson 167296d6407fSRichard Henderson nullify_over(ctx); 167396d6407fSRichard Henderson 167496d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1675fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 167696d6407fSRichard Henderson save_frd(rt, tmp); 167796d6407fSRichard Henderson 167896d6407fSRichard Henderson if (rt == 0) { 1679ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 168096d6407fSRichard Henderson } 168196d6407fSRichard Henderson 1682740038d7SRichard Henderson return nullify_end(ctx); 1683740038d7SRichard Henderson } 1684740038d7SRichard Henderson 1685740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1686740038d7SRichard Henderson { 1687740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1688740038d7SRichard Henderson a->disp, a->sp, a->m); 168996d6407fSRichard Henderson } 169096d6407fSRichard Henderson 16911cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1692c53e401eSRichard Henderson int64_t disp, unsigned sp, 169314776ab5STony Nguyen int modify, MemOp mop) 169496d6407fSRichard Henderson { 169596d6407fSRichard Henderson nullify_over(ctx); 16966fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 16971cd012a5SRichard Henderson return nullify_end(ctx); 169896d6407fSRichard Henderson } 169996d6407fSRichard Henderson 1700740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1701c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 170286f8d05fSRichard Henderson unsigned sp, int modify) 170396d6407fSRichard Henderson { 170496d6407fSRichard Henderson TCGv_i32 tmp; 170596d6407fSRichard Henderson 170696d6407fSRichard Henderson nullify_over(ctx); 170796d6407fSRichard Henderson 170896d6407fSRichard Henderson tmp = load_frw_i32(rt); 170986f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 171096d6407fSRichard Henderson 1711740038d7SRichard Henderson return nullify_end(ctx); 171296d6407fSRichard Henderson } 171396d6407fSRichard Henderson 1714740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1715740038d7SRichard Henderson { 1716740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1717740038d7SRichard Henderson a->disp, a->sp, a->m); 1718740038d7SRichard Henderson } 1719740038d7SRichard Henderson 1720740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1721c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 172286f8d05fSRichard Henderson unsigned sp, int modify) 172396d6407fSRichard Henderson { 172496d6407fSRichard Henderson TCGv_i64 tmp; 172596d6407fSRichard Henderson 172696d6407fSRichard Henderson nullify_over(ctx); 172796d6407fSRichard Henderson 172896d6407fSRichard Henderson tmp = load_frd(rt); 1729fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 173096d6407fSRichard Henderson 1731740038d7SRichard Henderson return nullify_end(ctx); 1732740038d7SRichard Henderson } 1733740038d7SRichard Henderson 1734740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1735740038d7SRichard Henderson { 1736740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1737740038d7SRichard Henderson a->disp, a->sp, a->m); 173896d6407fSRichard Henderson } 173996d6407fSRichard Henderson 17401ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1741ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1742ebe9383cSRichard Henderson { 1743ebe9383cSRichard Henderson TCGv_i32 tmp; 1744ebe9383cSRichard Henderson 1745ebe9383cSRichard Henderson nullify_over(ctx); 1746ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1747ebe9383cSRichard Henderson 1748ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1749ebe9383cSRichard Henderson 1750ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 17511ca74648SRichard Henderson return nullify_end(ctx); 1752ebe9383cSRichard Henderson } 1753ebe9383cSRichard Henderson 17541ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1755ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1756ebe9383cSRichard Henderson { 1757ebe9383cSRichard Henderson TCGv_i32 dst; 1758ebe9383cSRichard Henderson TCGv_i64 src; 1759ebe9383cSRichard Henderson 1760ebe9383cSRichard Henderson nullify_over(ctx); 1761ebe9383cSRichard Henderson src = load_frd(ra); 1762ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1763ebe9383cSRichard Henderson 1764ad75a51eSRichard Henderson func(dst, tcg_env, src); 1765ebe9383cSRichard Henderson 1766ebe9383cSRichard Henderson save_frw_i32(rt, dst); 17671ca74648SRichard Henderson return nullify_end(ctx); 1768ebe9383cSRichard Henderson } 1769ebe9383cSRichard Henderson 17701ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1771ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1772ebe9383cSRichard Henderson { 1773ebe9383cSRichard Henderson TCGv_i64 tmp; 1774ebe9383cSRichard Henderson 1775ebe9383cSRichard Henderson nullify_over(ctx); 1776ebe9383cSRichard Henderson tmp = load_frd0(ra); 1777ebe9383cSRichard Henderson 1778ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1779ebe9383cSRichard Henderson 1780ebe9383cSRichard Henderson save_frd(rt, tmp); 17811ca74648SRichard Henderson return nullify_end(ctx); 1782ebe9383cSRichard Henderson } 1783ebe9383cSRichard Henderson 17841ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1785ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1786ebe9383cSRichard Henderson { 1787ebe9383cSRichard Henderson TCGv_i32 src; 1788ebe9383cSRichard Henderson TCGv_i64 dst; 1789ebe9383cSRichard Henderson 1790ebe9383cSRichard Henderson nullify_over(ctx); 1791ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1792ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1793ebe9383cSRichard Henderson 1794ad75a51eSRichard Henderson func(dst, tcg_env, src); 1795ebe9383cSRichard Henderson 1796ebe9383cSRichard Henderson save_frd(rt, dst); 17971ca74648SRichard Henderson return nullify_end(ctx); 1798ebe9383cSRichard Henderson } 1799ebe9383cSRichard Henderson 18001ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1801ebe9383cSRichard Henderson unsigned ra, unsigned rb, 180231234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1803ebe9383cSRichard Henderson { 1804ebe9383cSRichard Henderson TCGv_i32 a, b; 1805ebe9383cSRichard Henderson 1806ebe9383cSRichard Henderson nullify_over(ctx); 1807ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1808ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1809ebe9383cSRichard Henderson 1810ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1811ebe9383cSRichard Henderson 1812ebe9383cSRichard Henderson save_frw_i32(rt, a); 18131ca74648SRichard Henderson return nullify_end(ctx); 1814ebe9383cSRichard Henderson } 1815ebe9383cSRichard Henderson 18161ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1817ebe9383cSRichard Henderson unsigned ra, unsigned rb, 181831234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1819ebe9383cSRichard Henderson { 1820ebe9383cSRichard Henderson TCGv_i64 a, b; 1821ebe9383cSRichard Henderson 1822ebe9383cSRichard Henderson nullify_over(ctx); 1823ebe9383cSRichard Henderson a = load_frd0(ra); 1824ebe9383cSRichard Henderson b = load_frd0(rb); 1825ebe9383cSRichard Henderson 1826ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1827ebe9383cSRichard Henderson 1828ebe9383cSRichard Henderson save_frd(rt, a); 18291ca74648SRichard Henderson return nullify_end(ctx); 1830ebe9383cSRichard Henderson } 1831ebe9383cSRichard Henderson 183298cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 183398cd9ca7SRichard Henderson have already had nullification handled. */ 18342644f80bSRichard Henderson static bool do_dbranch(DisasContext *ctx, int64_t disp, 183598cd9ca7SRichard Henderson unsigned link, bool is_n) 183698cd9ca7SRichard Henderson { 1837*bc921866SRichard Henderson ctx->iaq_j = iaqe_branchi(ctx, disp); 18382644f80bSRichard Henderson 183998cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 184043541db0SRichard Henderson install_link(ctx, link, false); 184198cd9ca7SRichard Henderson if (is_n) { 1842d08ad0e0SRichard Henderson if (use_nullify_skip(ctx)) { 1843d08ad0e0SRichard Henderson nullify_set(ctx, 0); 1844*bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL); 1845d08ad0e0SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 1846d08ad0e0SRichard Henderson return true; 1847d08ad0e0SRichard Henderson } 184898cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 184998cd9ca7SRichard Henderson } 1850*bc921866SRichard Henderson ctx->iaq_n = &ctx->iaq_j; 185198cd9ca7SRichard Henderson } else { 185298cd9ca7SRichard Henderson nullify_over(ctx); 185398cd9ca7SRichard Henderson 185443541db0SRichard Henderson install_link(ctx, link, false); 185598cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 185698cd9ca7SRichard Henderson nullify_set(ctx, 0); 1857*bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_j, NULL); 185898cd9ca7SRichard Henderson } else { 185998cd9ca7SRichard Henderson nullify_set(ctx, is_n); 1860*bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_b, &ctx->iaq_j); 186198cd9ca7SRichard Henderson } 186231234768SRichard Henderson nullify_end(ctx); 186398cd9ca7SRichard Henderson 186498cd9ca7SRichard Henderson nullify_set(ctx, 0); 1865*bc921866SRichard Henderson gen_goto_tb(ctx, 1, &ctx->iaq_b, NULL); 186631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 186798cd9ca7SRichard Henderson } 186801afb7beSRichard Henderson return true; 186998cd9ca7SRichard Henderson } 187098cd9ca7SRichard Henderson 187198cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 187298cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1873c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 187498cd9ca7SRichard Henderson DisasCond *cond) 187598cd9ca7SRichard Henderson { 1876*bc921866SRichard Henderson DisasIAQE next; 187798cd9ca7SRichard Henderson TCGLabel *taken = NULL; 187898cd9ca7SRichard Henderson TCGCond c = cond->c; 187998cd9ca7SRichard Henderson bool n; 188098cd9ca7SRichard Henderson 188198cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 188298cd9ca7SRichard Henderson 188398cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 188498cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 18852644f80bSRichard Henderson return do_dbranch(ctx, disp, 0, is_n && disp >= 0); 188698cd9ca7SRichard Henderson } 188798cd9ca7SRichard Henderson 188898cd9ca7SRichard Henderson taken = gen_new_label(); 18896fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 189098cd9ca7SRichard Henderson cond_free(cond); 189198cd9ca7SRichard Henderson 189298cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 189398cd9ca7SRichard Henderson n = is_n && disp < 0; 189498cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 189598cd9ca7SRichard Henderson nullify_set(ctx, 0); 1896*bc921866SRichard Henderson next = iaqe_incr(&ctx->iaq_b, 4); 1897*bc921866SRichard Henderson gen_goto_tb(ctx, 0, &next, NULL); 189898cd9ca7SRichard Henderson } else { 189998cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 190098cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 190198cd9ca7SRichard Henderson ctx->null_lab = NULL; 190298cd9ca7SRichard Henderson } 190398cd9ca7SRichard Henderson nullify_set(ctx, n); 1904*bc921866SRichard Henderson gen_goto_tb(ctx, 0, &ctx->iaq_b, NULL); 190598cd9ca7SRichard Henderson } 190698cd9ca7SRichard Henderson 190798cd9ca7SRichard Henderson gen_set_label(taken); 190898cd9ca7SRichard Henderson 190998cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 191098cd9ca7SRichard Henderson n = is_n && disp >= 0; 1911*bc921866SRichard Henderson 1912*bc921866SRichard Henderson next = iaqe_branchi(ctx, disp); 191398cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 191498cd9ca7SRichard Henderson nullify_set(ctx, 0); 1915*bc921866SRichard Henderson gen_goto_tb(ctx, 1, &next, NULL); 191698cd9ca7SRichard Henderson } else { 191798cd9ca7SRichard Henderson nullify_set(ctx, n); 1918*bc921866SRichard Henderson gen_goto_tb(ctx, 1, &ctx->iaq_b, &next); 191998cd9ca7SRichard Henderson } 192098cd9ca7SRichard Henderson 192198cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 192298cd9ca7SRichard Henderson if (ctx->null_lab) { 192398cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 192498cd9ca7SRichard Henderson ctx->null_lab = NULL; 192531234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 192698cd9ca7SRichard Henderson } else { 192731234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 192898cd9ca7SRichard Henderson } 192901afb7beSRichard Henderson return true; 193098cd9ca7SRichard Henderson } 193198cd9ca7SRichard Henderson 1932*bc921866SRichard Henderson /* 1933*bc921866SRichard Henderson * Emit an unconditional branch to an indirect target, in ctx->iaq_j. 1934*bc921866SRichard Henderson * This handles nullification of the branch itself. 1935*bc921866SRichard Henderson */ 1936*bc921866SRichard Henderson static bool do_ibranch(DisasContext *ctx, unsigned link, 1937*bc921866SRichard Henderson bool with_sr0, bool is_n) 193898cd9ca7SRichard Henderson { 1939d582c1faSRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 1940019f4159SRichard Henderson install_link(ctx, link, with_sr0); 194198cd9ca7SRichard Henderson if (is_n) { 1942c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1943*bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_j, NULL); 1944c301f34eSRichard Henderson nullify_set(ctx, 0); 194531234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 194601afb7beSRichard Henderson return true; 1947c301f34eSRichard Henderson } 194898cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 194998cd9ca7SRichard Henderson } 1950*bc921866SRichard Henderson ctx->iaq_n = &ctx->iaq_j; 1951d582c1faSRichard Henderson return true; 1952d582c1faSRichard Henderson } 195398cd9ca7SRichard Henderson 1954d582c1faSRichard Henderson nullify_over(ctx); 1955d582c1faSRichard Henderson 1956019f4159SRichard Henderson install_link(ctx, link, with_sr0); 1957d582c1faSRichard Henderson if (is_n && use_nullify_skip(ctx)) { 1958*bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_j, NULL); 1959d582c1faSRichard Henderson nullify_set(ctx, 0); 1960d582c1faSRichard Henderson } else { 1961*bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_b, &ctx->iaq_j); 1962d582c1faSRichard Henderson nullify_set(ctx, is_n); 1963d582c1faSRichard Henderson } 1964d582c1faSRichard Henderson 19657f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 1966d582c1faSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 196701afb7beSRichard Henderson return nullify_end(ctx); 196898cd9ca7SRichard Henderson } 196998cd9ca7SRichard Henderson 1970660eefe1SRichard Henderson /* Implement 1971660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1972660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1973660eefe1SRichard Henderson * else 1974660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1975660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1976660eefe1SRichard Henderson */ 19776fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1978660eefe1SRichard Henderson { 19791874e6c2SRichard Henderson TCGv_i64 dest = tcg_temp_new_i64(); 1980660eefe1SRichard Henderson switch (ctx->privilege) { 1981660eefe1SRichard Henderson case 0: 1982660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 19831874e6c2SRichard Henderson tcg_gen_mov_i64(dest, offset); 19841874e6c2SRichard Henderson break; 1985660eefe1SRichard Henderson case 3: 1986993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 19876fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1988660eefe1SRichard Henderson break; 1989660eefe1SRichard Henderson default: 19906fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 19916fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 19920bb02029SRichard Henderson tcg_gen_umax_i64(dest, dest, offset); 1993660eefe1SRichard Henderson break; 1994660eefe1SRichard Henderson } 1995660eefe1SRichard Henderson return dest; 1996660eefe1SRichard Henderson } 1997660eefe1SRichard Henderson 1998ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 19997ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 20007ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 20017ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 20027ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 20037ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 20047ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 20057ad439dfSRichard Henderson aforementioned BE. */ 200631234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 20077ad439dfSRichard Henderson { 20087ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 20097ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 20108b81968cSMichael Tokarev next insn within the privileged page. */ 20117ad439dfSRichard Henderson switch (ctx->null_cond.c) { 20127ad439dfSRichard Henderson case TCG_COND_NEVER: 20137ad439dfSRichard Henderson break; 20147ad439dfSRichard Henderson case TCG_COND_ALWAYS: 20156fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 20167ad439dfSRichard Henderson goto do_sigill; 20177ad439dfSRichard Henderson default: 20187ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 20197ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 20207ad439dfSRichard Henderson g_assert_not_reached(); 20217ad439dfSRichard Henderson } 20227ad439dfSRichard Henderson 20237ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 20247ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 20257ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 20267ad439dfSRichard Henderson under such conditions. */ 2027*bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 20287ad439dfSRichard Henderson goto do_sigill; 20297ad439dfSRichard Henderson } 20307ad439dfSRichard Henderson 2031*bc921866SRichard Henderson switch (ctx->iaq_f.disp & -4) { 20327ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 20332986721dSRichard Henderson gen_excp_1(EXCP_IMP); 203431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 203531234768SRichard Henderson break; 20367ad439dfSRichard Henderson 20377ad439dfSRichard Henderson case 0xb0: /* LWS */ 20387ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 203931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 204031234768SRichard Henderson break; 20417ad439dfSRichard Henderson 20427ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 2043*bc921866SRichard Henderson { 2044*bc921866SRichard Henderson DisasIAQE next = { .base = tcg_temp_new_i64() }; 2045*bc921866SRichard Henderson 2046*bc921866SRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, 2047*bc921866SRichard Henderson offsetof(CPUHPPAState, cr[27])); 2048*bc921866SRichard Henderson tcg_gen_ori_i64(next.base, cpu_gr[31], 3); 2049*bc921866SRichard Henderson install_iaq_entries(ctx, &next, NULL); 205031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 2051*bc921866SRichard Henderson } 205231234768SRichard Henderson break; 20537ad439dfSRichard Henderson 20547ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 20557ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 205631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 205731234768SRichard Henderson break; 20587ad439dfSRichard Henderson 20597ad439dfSRichard Henderson default: 20607ad439dfSRichard Henderson do_sigill: 20612986721dSRichard Henderson gen_excp_1(EXCP_ILL); 206231234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 206331234768SRichard Henderson break; 20647ad439dfSRichard Henderson } 20657ad439dfSRichard Henderson } 2066ba1d0b44SRichard Henderson #endif 20677ad439dfSRichard Henderson 2068deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 2069b2167459SRichard Henderson { 2070b2167459SRichard Henderson cond_free(&ctx->null_cond); 207131234768SRichard Henderson return true; 2072b2167459SRichard Henderson } 2073b2167459SRichard Henderson 207440f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 207598a9cb79SRichard Henderson { 207631234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 207798a9cb79SRichard Henderson } 207898a9cb79SRichard Henderson 2079e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 208098a9cb79SRichard Henderson { 208198a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 208298a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 208398a9cb79SRichard Henderson 208498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 208531234768SRichard Henderson return true; 208698a9cb79SRichard Henderson } 208798a9cb79SRichard Henderson 2088c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 208998a9cb79SRichard Henderson { 2090*bc921866SRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 209198a9cb79SRichard Henderson 2092*bc921866SRichard Henderson copy_iaoq_entry(ctx, dest, &ctx->iaq_f); 2093*bc921866SRichard Henderson tcg_gen_andi_i64(dest, dest, -4); 2094*bc921866SRichard Henderson 2095*bc921866SRichard Henderson save_gpr(ctx, a->t, dest); 209698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 209731234768SRichard Henderson return true; 209898a9cb79SRichard Henderson } 209998a9cb79SRichard Henderson 2100c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 210198a9cb79SRichard Henderson { 2102c603e14aSRichard Henderson unsigned rt = a->t; 2103c603e14aSRichard Henderson unsigned rs = a->sp; 210433423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 210598a9cb79SRichard Henderson 210633423472SRichard Henderson load_spr(ctx, t0, rs); 210733423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 210833423472SRichard Henderson 2109967662cdSRichard Henderson save_gpr(ctx, rt, t0); 211098a9cb79SRichard Henderson 211198a9cb79SRichard Henderson cond_free(&ctx->null_cond); 211231234768SRichard Henderson return true; 211398a9cb79SRichard Henderson } 211498a9cb79SRichard Henderson 2115c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 211698a9cb79SRichard Henderson { 2117c603e14aSRichard Henderson unsigned rt = a->t; 2118c603e14aSRichard Henderson unsigned ctl = a->r; 21196fd0c7bcSRichard Henderson TCGv_i64 tmp; 212098a9cb79SRichard Henderson 212198a9cb79SRichard Henderson switch (ctl) { 212235136a77SRichard Henderson case CR_SAR: 2123c603e14aSRichard Henderson if (a->e == 0) { 212498a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 212598a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 21266fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 212798a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 212835136a77SRichard Henderson goto done; 212998a9cb79SRichard Henderson } 213098a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 213135136a77SRichard Henderson goto done; 213235136a77SRichard Henderson case CR_IT: /* Interval Timer */ 213335136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 213435136a77SRichard Henderson nullify_over(ctx); 213598a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2136dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 213731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 213849c29d6cSRichard Henderson } 21390c58c1bcSRichard Henderson gen_helper_read_interval_timer(tmp); 214098a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 214131234768SRichard Henderson return nullify_end(ctx); 214298a9cb79SRichard Henderson case 26: 214398a9cb79SRichard Henderson case 27: 214498a9cb79SRichard Henderson break; 214598a9cb79SRichard Henderson default: 214698a9cb79SRichard Henderson /* All other control registers are privileged. */ 214735136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 214835136a77SRichard Henderson break; 214998a9cb79SRichard Henderson } 215098a9cb79SRichard Henderson 2151aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21526fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 215335136a77SRichard Henderson save_gpr(ctx, rt, tmp); 215435136a77SRichard Henderson 215535136a77SRichard Henderson done: 215698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 215731234768SRichard Henderson return true; 215898a9cb79SRichard Henderson } 215998a9cb79SRichard Henderson 2160c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 216133423472SRichard Henderson { 2162c603e14aSRichard Henderson unsigned rr = a->r; 2163c603e14aSRichard Henderson unsigned rs = a->sp; 2164967662cdSRichard Henderson TCGv_i64 tmp; 216533423472SRichard Henderson 216633423472SRichard Henderson if (rs >= 5) { 216733423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 216833423472SRichard Henderson } 216933423472SRichard Henderson nullify_over(ctx); 217033423472SRichard Henderson 2171967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2172967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 217333423472SRichard Henderson 217433423472SRichard Henderson if (rs >= 4) { 2175967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2176494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 217733423472SRichard Henderson } else { 2178967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 217933423472SRichard Henderson } 218033423472SRichard Henderson 218131234768SRichard Henderson return nullify_end(ctx); 218233423472SRichard Henderson } 218333423472SRichard Henderson 2184c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 218598a9cb79SRichard Henderson { 2186c603e14aSRichard Henderson unsigned ctl = a->t; 21876fd0c7bcSRichard Henderson TCGv_i64 reg; 21886fd0c7bcSRichard Henderson TCGv_i64 tmp; 218998a9cb79SRichard Henderson 219035136a77SRichard Henderson if (ctl == CR_SAR) { 21914845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2192aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21936fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 219498a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 219598a9cb79SRichard Henderson 219698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 219731234768SRichard Henderson return true; 219898a9cb79SRichard Henderson } 219998a9cb79SRichard Henderson 220035136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 220135136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 220235136a77SRichard Henderson 2203c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 220435136a77SRichard Henderson nullify_over(ctx); 22054c34bab0SHelge Deller 22064c34bab0SHelge Deller if (ctx->is_pa20) { 22074845f015SSven Schnelle reg = load_gpr(ctx, a->r); 22084c34bab0SHelge Deller } else { 22094c34bab0SHelge Deller reg = tcg_temp_new_i64(); 22104c34bab0SHelge Deller tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 22114c34bab0SHelge Deller } 22124845f015SSven Schnelle 221335136a77SRichard Henderson switch (ctl) { 221435136a77SRichard Henderson case CR_IT: 2215104281c1SRichard Henderson if (translator_io_start(&ctx->base)) { 2216104281c1SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2217104281c1SRichard Henderson } 2218ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 221935136a77SRichard Henderson break; 22204f5f2548SRichard Henderson case CR_EIRR: 22216ebebea7SRichard Henderson /* Helper modifies interrupt lines and is therefore IO. */ 22226ebebea7SRichard Henderson translator_io_start(&ctx->base); 2223ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 22246ebebea7SRichard Henderson /* Exit to re-evaluate interrupts in the main loop. */ 222531234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 22264f5f2548SRichard Henderson break; 22274f5f2548SRichard Henderson 222835136a77SRichard Henderson case CR_IIASQ: 222935136a77SRichard Henderson case CR_IIAOQ: 223035136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 223135136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2232aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22336fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 223435136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 22356fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 22366fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 223735136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 223835136a77SRichard Henderson break; 223935136a77SRichard Henderson 2240d5de20bdSSven Schnelle case CR_PID1: 2241d5de20bdSSven Schnelle case CR_PID2: 2242d5de20bdSSven Schnelle case CR_PID3: 2243d5de20bdSSven Schnelle case CR_PID4: 22446fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2245d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2246ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2247d5de20bdSSven Schnelle #endif 2248d5de20bdSSven Schnelle break; 2249d5de20bdSSven Schnelle 22506ebebea7SRichard Henderson case CR_EIEM: 22516ebebea7SRichard Henderson /* Exit to re-evaluate interrupts in the main loop. */ 22526ebebea7SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 22536ebebea7SRichard Henderson /* FALLTHRU */ 225435136a77SRichard Henderson default: 22556fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 225635136a77SRichard Henderson break; 225735136a77SRichard Henderson } 225831234768SRichard Henderson return nullify_end(ctx); 22594f5f2548SRichard Henderson #endif 226035136a77SRichard Henderson } 226135136a77SRichard Henderson 2262c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 226398a9cb79SRichard Henderson { 2264aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 226598a9cb79SRichard Henderson 22666fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 22676fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 226898a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 226998a9cb79SRichard Henderson 227098a9cb79SRichard Henderson cond_free(&ctx->null_cond); 227131234768SRichard Henderson return true; 227298a9cb79SRichard Henderson } 227398a9cb79SRichard Henderson 2274e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 227598a9cb79SRichard Henderson { 22766fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 227798a9cb79SRichard Henderson 22782330504cSHelge Deller #ifdef CONFIG_USER_ONLY 22792330504cSHelge Deller /* We don't implement space registers in user mode. */ 22806fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 22812330504cSHelge Deller #else 2282967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2283967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 22842330504cSHelge Deller #endif 2285e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 228698a9cb79SRichard Henderson 228798a9cb79SRichard Henderson cond_free(&ctx->null_cond); 228831234768SRichard Henderson return true; 228998a9cb79SRichard Henderson } 229098a9cb79SRichard Henderson 2291e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2292e36f27efSRichard Henderson { 22937b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY 2294e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22957b2d70a1SHelge Deller #else 22966fd0c7bcSRichard Henderson TCGv_i64 tmp; 2297e1b5a5edSRichard Henderson 22987b2d70a1SHelge Deller /* HP-UX 11i and HP ODE use rsm for read-access to PSW */ 22997b2d70a1SHelge Deller if (a->i) { 23007b2d70a1SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 23017b2d70a1SHelge Deller } 23027b2d70a1SHelge Deller 2303e1b5a5edSRichard Henderson nullify_over(ctx); 2304e1b5a5edSRichard Henderson 2305aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 23066fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 23076fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2308ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2309e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2310e1b5a5edSRichard Henderson 2311e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 231231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 231331234768SRichard Henderson return nullify_end(ctx); 2314e36f27efSRichard Henderson #endif 2315e1b5a5edSRichard Henderson } 2316e1b5a5edSRichard Henderson 2317e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2318e1b5a5edSRichard Henderson { 2319e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2320e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 23216fd0c7bcSRichard Henderson TCGv_i64 tmp; 2322e1b5a5edSRichard Henderson 2323e1b5a5edSRichard Henderson nullify_over(ctx); 2324e1b5a5edSRichard Henderson 2325aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 23266fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 23276fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2328ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2329e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2330e1b5a5edSRichard Henderson 2331e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 233231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 233331234768SRichard Henderson return nullify_end(ctx); 2334e36f27efSRichard Henderson #endif 2335e1b5a5edSRichard Henderson } 2336e1b5a5edSRichard Henderson 2337c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2338e1b5a5edSRichard Henderson { 2339e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2340c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 23416fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2342e1b5a5edSRichard Henderson nullify_over(ctx); 2343e1b5a5edSRichard Henderson 2344c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2345aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2346ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2347e1b5a5edSRichard Henderson 2348e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 234931234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 235031234768SRichard Henderson return nullify_end(ctx); 2351c603e14aSRichard Henderson #endif 2352e1b5a5edSRichard Henderson } 2353f49b3537SRichard Henderson 2354e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2355f49b3537SRichard Henderson { 2356f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2357e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2358f49b3537SRichard Henderson nullify_over(ctx); 2359f49b3537SRichard Henderson 2360e36f27efSRichard Henderson if (rfi_r) { 2361ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2362f49b3537SRichard Henderson } else { 2363ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2364f49b3537SRichard Henderson } 236531234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 236607ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 236731234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2368f49b3537SRichard Henderson 236931234768SRichard Henderson return nullify_end(ctx); 2370e36f27efSRichard Henderson #endif 2371f49b3537SRichard Henderson } 23726210db05SHelge Deller 2373e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2374e36f27efSRichard Henderson { 2375e36f27efSRichard Henderson return do_rfi(ctx, false); 2376e36f27efSRichard Henderson } 2377e36f27efSRichard Henderson 2378e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2379e36f27efSRichard Henderson { 2380e36f27efSRichard Henderson return do_rfi(ctx, true); 2381e36f27efSRichard Henderson } 2382e36f27efSRichard Henderson 238396927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 23846210db05SHelge Deller { 23856210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 238696927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 23876210db05SHelge Deller nullify_over(ctx); 2388ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 238931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 239031234768SRichard Henderson return nullify_end(ctx); 239196927adbSRichard Henderson #endif 23926210db05SHelge Deller } 239396927adbSRichard Henderson 239496927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 239596927adbSRichard Henderson { 239696927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 239796927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 239896927adbSRichard Henderson nullify_over(ctx); 2399ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 240096927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 240196927adbSRichard Henderson return nullify_end(ctx); 240296927adbSRichard Henderson #endif 240396927adbSRichard Henderson } 2404e1b5a5edSRichard Henderson 2405558c09beSRichard Henderson static bool do_getshadowregs(DisasContext *ctx) 24064a4554c6SHelge Deller { 24074a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24084a4554c6SHelge Deller nullify_over(ctx); 2409558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0])); 2410558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1])); 2411558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2])); 2412558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3])); 2413558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4])); 2414558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5])); 2415558c09beSRichard Henderson tcg_gen_ld_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6])); 24164a4554c6SHelge Deller return nullify_end(ctx); 2417558c09beSRichard Henderson } 2418558c09beSRichard Henderson 24193bdf2081SHelge Deller static bool do_putshadowregs(DisasContext *ctx) 24203bdf2081SHelge Deller { 24213bdf2081SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24223bdf2081SHelge Deller nullify_over(ctx); 24233bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[1], tcg_env, offsetof(CPUHPPAState, shadow[0])); 24243bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[8], tcg_env, offsetof(CPUHPPAState, shadow[1])); 24253bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[9], tcg_env, offsetof(CPUHPPAState, shadow[2])); 24263bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[16], tcg_env, offsetof(CPUHPPAState, shadow[3])); 24273bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[17], tcg_env, offsetof(CPUHPPAState, shadow[4])); 24283bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[24], tcg_env, offsetof(CPUHPPAState, shadow[5])); 24293bdf2081SHelge Deller tcg_gen_st_i64(cpu_gr[25], tcg_env, offsetof(CPUHPPAState, shadow[6])); 24303bdf2081SHelge Deller return nullify_end(ctx); 24313bdf2081SHelge Deller } 24323bdf2081SHelge Deller 2433558c09beSRichard Henderson static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 2434558c09beSRichard Henderson { 2435558c09beSRichard Henderson return do_getshadowregs(ctx); 24364a4554c6SHelge Deller } 24374a4554c6SHelge Deller 2438deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 243998a9cb79SRichard Henderson { 2440deee69a1SRichard Henderson if (a->m) { 24416fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 24426fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 24436fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 244498a9cb79SRichard Henderson 244598a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 24466fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2447deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2448deee69a1SRichard Henderson } 244998a9cb79SRichard Henderson cond_free(&ctx->null_cond); 245031234768SRichard Henderson return true; 245198a9cb79SRichard Henderson } 245298a9cb79SRichard Henderson 2453ad1fdacdSSven Schnelle static bool trans_fic(DisasContext *ctx, arg_ldst *a) 2454ad1fdacdSSven Schnelle { 2455ad1fdacdSSven Schnelle /* End TB for flush instruction cache, so we pick up new insns. */ 2456ad1fdacdSSven Schnelle ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2457ad1fdacdSSven Schnelle return trans_nop_addrx(ctx, a); 2458ad1fdacdSSven Schnelle } 2459ad1fdacdSSven Schnelle 2460deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 246198a9cb79SRichard Henderson { 24626fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2463eed14219SRichard Henderson TCGv_i32 level, want; 24646fd0c7bcSRichard Henderson TCGv_i64 addr; 246598a9cb79SRichard Henderson 246698a9cb79SRichard Henderson nullify_over(ctx); 246798a9cb79SRichard Henderson 2468deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2469deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2470eed14219SRichard Henderson 2471deee69a1SRichard Henderson if (a->imm) { 2472e5d487c9SRichard Henderson level = tcg_constant_i32(a->ri & 3); 247398a9cb79SRichard Henderson } else { 2474eed14219SRichard Henderson level = tcg_temp_new_i32(); 24756fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2476eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 247798a9cb79SRichard Henderson } 247829dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2479eed14219SRichard Henderson 2480ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2481eed14219SRichard Henderson 2482deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 248331234768SRichard Henderson return nullify_end(ctx); 248498a9cb79SRichard Henderson } 248598a9cb79SRichard Henderson 2486deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 24878d6ae7fbSRichard Henderson { 24888577f354SRichard Henderson if (ctx->is_pa20) { 24898577f354SRichard Henderson return false; 24908577f354SRichard Henderson } 2491deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2492deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24936fd0c7bcSRichard Henderson TCGv_i64 addr; 24946fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 24958d6ae7fbSRichard Henderson 24968d6ae7fbSRichard Henderson nullify_over(ctx); 24978d6ae7fbSRichard Henderson 2498deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2499deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2500deee69a1SRichard Henderson if (a->addr) { 25018577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 25028d6ae7fbSRichard Henderson } else { 25038577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 25048d6ae7fbSRichard Henderson } 25058d6ae7fbSRichard Henderson 250632dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 250732dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 250831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 250931234768SRichard Henderson } 251031234768SRichard Henderson return nullify_end(ctx); 2511deee69a1SRichard Henderson #endif 25128d6ae7fbSRichard Henderson } 251363300a00SRichard Henderson 2514eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 251563300a00SRichard Henderson { 2516deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2517deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 25186fd0c7bcSRichard Henderson TCGv_i64 addr; 25196fd0c7bcSRichard Henderson TCGv_i64 ofs; 252063300a00SRichard Henderson 252163300a00SRichard Henderson nullify_over(ctx); 252263300a00SRichard Henderson 2523deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2524eb25d10fSHelge Deller 2525eb25d10fSHelge Deller /* 2526eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2527eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2528eb25d10fSHelge Deller */ 2529eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2530eb25d10fSHelge Deller if (ctx->is_pa20) { 2531eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 253263300a00SRichard Henderson } 2533eb25d10fSHelge Deller 2534eb25d10fSHelge Deller if (local) { 2535eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 253663300a00SRichard Henderson } else { 2537ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 253863300a00SRichard Henderson } 253963300a00SRichard Henderson 2540eb25d10fSHelge Deller if (a->m) { 2541eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2542eb25d10fSHelge Deller } 2543eb25d10fSHelge Deller 2544eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2545eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2546eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2547eb25d10fSHelge Deller } 2548eb25d10fSHelge Deller return nullify_end(ctx); 2549eb25d10fSHelge Deller #endif 2550eb25d10fSHelge Deller } 2551eb25d10fSHelge Deller 2552eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2553eb25d10fSHelge Deller { 2554eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2555eb25d10fSHelge Deller } 2556eb25d10fSHelge Deller 2557eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2558eb25d10fSHelge Deller { 2559eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2560eb25d10fSHelge Deller } 2561eb25d10fSHelge Deller 2562eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2563eb25d10fSHelge Deller { 2564eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2565eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2566eb25d10fSHelge Deller nullify_over(ctx); 2567eb25d10fSHelge Deller 2568eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2569eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2570eb25d10fSHelge Deller 257163300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 257232dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 257331234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 257431234768SRichard Henderson } 257531234768SRichard Henderson return nullify_end(ctx); 2576deee69a1SRichard Henderson #endif 257763300a00SRichard Henderson } 25782dfcca9fSRichard Henderson 25796797c315SNick Hudson /* 25806797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 25816797c315SNick Hudson * See 25826797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 25836797c315SNick Hudson * page 13-9 (195/206) 25846797c315SNick Hudson */ 25856797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 25866797c315SNick Hudson { 25878577f354SRichard Henderson if (ctx->is_pa20) { 25888577f354SRichard Henderson return false; 25898577f354SRichard Henderson } 25906797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 25916797c315SNick Hudson #ifndef CONFIG_USER_ONLY 25926fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 25936fd0c7bcSRichard Henderson TCGv_i64 reg; 25946797c315SNick Hudson 25956797c315SNick Hudson nullify_over(ctx); 25966797c315SNick Hudson 25976797c315SNick Hudson /* 25986797c315SNick Hudson * FIXME: 25996797c315SNick Hudson * if (not (pcxl or pcxl2)) 26006797c315SNick Hudson * return gen_illegal(ctx); 26016797c315SNick Hudson */ 26026797c315SNick Hudson 26036fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 26046fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 26056fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 26066797c315SNick Hudson 2607ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 26086797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 26096797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2610ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 26116797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 26126797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 26136797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2614d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 26156797c315SNick Hudson 26166797c315SNick Hudson reg = load_gpr(ctx, a->r); 26176797c315SNick Hudson if (a->addr) { 26188577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 26196797c315SNick Hudson } else { 26208577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 26216797c315SNick Hudson } 26226797c315SNick Hudson 26236797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 26246797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 26256797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 26266797c315SNick Hudson } 26276797c315SNick Hudson return nullify_end(ctx); 26286797c315SNick Hudson #endif 26296797c315SNick Hudson } 26306797c315SNick Hudson 26318577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 26328577f354SRichard Henderson { 26338577f354SRichard Henderson if (!ctx->is_pa20) { 26348577f354SRichard Henderson return false; 26358577f354SRichard Henderson } 26368577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 26378577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 26388577f354SRichard Henderson nullify_over(ctx); 26398577f354SRichard Henderson { 26408577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 26418577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 26428577f354SRichard Henderson 26438577f354SRichard Henderson if (a->data) { 26448577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 26458577f354SRichard Henderson } else { 26468577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 26478577f354SRichard Henderson } 26488577f354SRichard Henderson } 26498577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 26508577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 26518577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 26528577f354SRichard Henderson } 26538577f354SRichard Henderson return nullify_end(ctx); 26548577f354SRichard Henderson #endif 26558577f354SRichard Henderson } 26568577f354SRichard Henderson 2657deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 26582dfcca9fSRichard Henderson { 2659deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2660deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 26616fd0c7bcSRichard Henderson TCGv_i64 vaddr; 26626fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 26632dfcca9fSRichard Henderson 26642dfcca9fSRichard Henderson nullify_over(ctx); 26652dfcca9fSRichard Henderson 2666deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 26672dfcca9fSRichard Henderson 2668aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2669ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 26702dfcca9fSRichard Henderson 26712dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2672deee69a1SRichard Henderson if (a->m) { 2673deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 26742dfcca9fSRichard Henderson } 2675deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 26762dfcca9fSRichard Henderson 267731234768SRichard Henderson return nullify_end(ctx); 2678deee69a1SRichard Henderson #endif 26792dfcca9fSRichard Henderson } 268043a97b81SRichard Henderson 2681deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 268243a97b81SRichard Henderson { 268343a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 268443a97b81SRichard Henderson 268543a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 268643a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 268743a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 268843a97b81SRichard Henderson since the entire address space is coherent. */ 2689a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 269043a97b81SRichard Henderson 269131234768SRichard Henderson cond_free(&ctx->null_cond); 269231234768SRichard Henderson return true; 269343a97b81SRichard Henderson } 269498a9cb79SRichard Henderson 2695faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2696b2167459SRichard Henderson { 26970c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2698b2167459SRichard Henderson } 2699b2167459SRichard Henderson 2700faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2701b2167459SRichard Henderson { 27020c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2703b2167459SRichard Henderson } 2704b2167459SRichard Henderson 2705faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2706b2167459SRichard Henderson { 27070c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2708b2167459SRichard Henderson } 2709b2167459SRichard Henderson 2710faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2711b2167459SRichard Henderson { 27120c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 27130c982a28SRichard Henderson } 2714b2167459SRichard Henderson 2715faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 27160c982a28SRichard Henderson { 27170c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 27180c982a28SRichard Henderson } 27190c982a28SRichard Henderson 272063c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 27210c982a28SRichard Henderson { 27220c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 27230c982a28SRichard Henderson } 27240c982a28SRichard Henderson 272563c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 27260c982a28SRichard Henderson { 27270c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 27280c982a28SRichard Henderson } 27290c982a28SRichard Henderson 273063c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 27310c982a28SRichard Henderson { 27320c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 27330c982a28SRichard Henderson } 27340c982a28SRichard Henderson 273563c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 27360c982a28SRichard Henderson { 27370c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 27380c982a28SRichard Henderson } 27390c982a28SRichard Henderson 274063c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 27410c982a28SRichard Henderson { 27420c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 27430c982a28SRichard Henderson } 27440c982a28SRichard Henderson 274563c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 27460c982a28SRichard Henderson { 27470c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 27480c982a28SRichard Henderson } 27490c982a28SRichard Henderson 2750fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 27510c982a28SRichard Henderson { 27526fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 27530c982a28SRichard Henderson } 27540c982a28SRichard Henderson 2755fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 27560c982a28SRichard Henderson { 27576fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 27580c982a28SRichard Henderson } 27590c982a28SRichard Henderson 2760fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 27610c982a28SRichard Henderson { 27620c982a28SRichard Henderson if (a->cf == 0) { 27630c982a28SRichard Henderson unsigned r2 = a->r2; 27640c982a28SRichard Henderson unsigned r1 = a->r1; 27650c982a28SRichard Henderson unsigned rt = a->t; 27660c982a28SRichard Henderson 27677aee8189SRichard Henderson if (rt == 0) { /* NOP */ 27687aee8189SRichard Henderson cond_free(&ctx->null_cond); 27697aee8189SRichard Henderson return true; 27707aee8189SRichard Henderson } 27717aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2772b2167459SRichard Henderson if (r1 == 0) { 27736fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 27746fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2775b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2776b2167459SRichard Henderson } else { 2777b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2778b2167459SRichard Henderson } 2779b2167459SRichard Henderson cond_free(&ctx->null_cond); 278031234768SRichard Henderson return true; 2781b2167459SRichard Henderson } 27827aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 27837aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 27847aee8189SRichard Henderson * 27857aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 27867aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 27877aee8189SRichard Henderson * currently implemented as idle. 27887aee8189SRichard Henderson */ 27897aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 27907aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 27917aee8189SRichard Henderson until the next timer interrupt. */ 27927aee8189SRichard Henderson nullify_over(ctx); 27937aee8189SRichard Henderson 27947aee8189SRichard Henderson /* Advance the instruction queue. */ 2795*bc921866SRichard Henderson install_iaq_entries(ctx, &ctx->iaq_b, NULL); 27967aee8189SRichard Henderson nullify_set(ctx, 0); 27977aee8189SRichard Henderson 27987aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2799ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 280029dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 28017aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 28027aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 28037aee8189SRichard Henderson 28047aee8189SRichard Henderson return nullify_end(ctx); 28057aee8189SRichard Henderson } 28067aee8189SRichard Henderson #endif 28077aee8189SRichard Henderson } 28086fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 28097aee8189SRichard Henderson } 2810b2167459SRichard Henderson 2811fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2812b2167459SRichard Henderson { 28136fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 28140c982a28SRichard Henderson } 28150c982a28SRichard Henderson 2816345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 28170c982a28SRichard Henderson { 28186fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2819b2167459SRichard Henderson 28200c982a28SRichard Henderson if (a->cf) { 2821b2167459SRichard Henderson nullify_over(ctx); 2822b2167459SRichard Henderson } 28230c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 28240c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2825345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 282631234768SRichard Henderson return nullify_end(ctx); 2827b2167459SRichard Henderson } 2828b2167459SRichard Henderson 2829af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2830b2167459SRichard Henderson { 283146bb3d46SRichard Henderson TCGv_i64 tcg_r1, tcg_r2, dest; 2832b2167459SRichard Henderson 28330c982a28SRichard Henderson if (a->cf) { 2834b2167459SRichard Henderson nullify_over(ctx); 2835b2167459SRichard Henderson } 283646bb3d46SRichard Henderson 28370c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 28380c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 283946bb3d46SRichard Henderson dest = dest_gpr(ctx, a->t); 284046bb3d46SRichard Henderson 284146bb3d46SRichard Henderson tcg_gen_xor_i64(dest, tcg_r1, tcg_r2); 284246bb3d46SRichard Henderson save_gpr(ctx, a->t, dest); 284346bb3d46SRichard Henderson 284446bb3d46SRichard Henderson cond_free(&ctx->null_cond); 284546bb3d46SRichard Henderson if (a->cf) { 284646bb3d46SRichard Henderson ctx->null_cond = do_unit_zero_cond(a->cf, a->d, dest); 284746bb3d46SRichard Henderson } 284846bb3d46SRichard Henderson 284931234768SRichard Henderson return nullify_end(ctx); 2850b2167459SRichard Henderson } 2851b2167459SRichard Henderson 2852af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2853b2167459SRichard Henderson { 28546fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2855b2167459SRichard Henderson 2856ababac16SRichard Henderson if (a->cf == 0) { 2857ababac16SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2858ababac16SRichard Henderson tmp = dest_gpr(ctx, a->t); 2859ababac16SRichard Henderson 2860ababac16SRichard Henderson if (a->r1 == 0) { 2861ababac16SRichard Henderson /* UADDCM r0,src,dst is the common idiom for dst = ~src. */ 2862ababac16SRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 2863ababac16SRichard Henderson } else { 2864ababac16SRichard Henderson /* 2865ababac16SRichard Henderson * Recall that r1 - r2 == r1 + ~r2 + 1. 2866ababac16SRichard Henderson * Thus r1 + ~r2 == r1 - r2 - 1, 2867ababac16SRichard Henderson * which does not require an extra temporary. 2868ababac16SRichard Henderson */ 2869ababac16SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 2870ababac16SRichard Henderson tcg_gen_sub_i64(tmp, tcg_r1, tcg_r2); 2871ababac16SRichard Henderson tcg_gen_subi_i64(tmp, tmp, 1); 2872b2167459SRichard Henderson } 2873ababac16SRichard Henderson save_gpr(ctx, a->t, tmp); 2874ababac16SRichard Henderson cond_free(&ctx->null_cond); 2875ababac16SRichard Henderson return true; 2876ababac16SRichard Henderson } 2877ababac16SRichard Henderson 2878ababac16SRichard Henderson nullify_over(ctx); 28790c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 28800c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2881aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 28826fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 288346bb3d46SRichard Henderson do_unit_addsub(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, true); 288431234768SRichard Henderson return nullify_end(ctx); 2885b2167459SRichard Henderson } 2886b2167459SRichard Henderson 2887af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2888b2167459SRichard Henderson { 28890c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 28900c982a28SRichard Henderson } 28910c982a28SRichard Henderson 2892af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 28930c982a28SRichard Henderson { 28940c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 28950c982a28SRichard Henderson } 28960c982a28SRichard Henderson 2897af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 28980c982a28SRichard Henderson { 28996fd0c7bcSRichard Henderson TCGv_i64 tmp; 2900b2167459SRichard Henderson 2901b2167459SRichard Henderson nullify_over(ctx); 2902b2167459SRichard Henderson 2903aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2904d0ae87a2SRichard Henderson tcg_gen_extract2_i64(tmp, cpu_psw_cb, cpu_psw_cb_msb, 4); 2905b2167459SRichard Henderson if (!is_i) { 29066fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2907b2167459SRichard Henderson } 29086fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 29096fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 291046bb3d46SRichard Henderson do_unit_addsub(ctx, a->t, load_gpr(ctx, a->r), tmp, 291146bb3d46SRichard Henderson a->cf, a->d, false, is_i); 291231234768SRichard Henderson return nullify_end(ctx); 2913b2167459SRichard Henderson } 2914b2167459SRichard Henderson 2915af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2916b2167459SRichard Henderson { 29170c982a28SRichard Henderson return do_dcor(ctx, a, false); 29180c982a28SRichard Henderson } 29190c982a28SRichard Henderson 2920af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 29210c982a28SRichard Henderson { 29220c982a28SRichard Henderson return do_dcor(ctx, a, true); 29230c982a28SRichard Henderson } 29240c982a28SRichard Henderson 29250c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 29260c982a28SRichard Henderson { 2927a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 2928b2167459SRichard Henderson 2929b2167459SRichard Henderson nullify_over(ctx); 2930b2167459SRichard Henderson 29310c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 29320c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2933b2167459SRichard Henderson 2934aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2935aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2936aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2937aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2938b2167459SRichard Henderson 2939b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 29406fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 29416fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2942b2167459SRichard Henderson 294372ca8753SRichard Henderson /* 294472ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 294572ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 294672ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 294772ca8753SRichard Henderson * proper inputs to the addition without movcond. 294872ca8753SRichard Henderson */ 29496fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 29506fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 29516fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 295272ca8753SRichard Henderson 2953a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2954a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2955a4db4a78SRichard Henderson addc, ctx->zero); 2956b2167459SRichard Henderson 2957b2167459SRichard Henderson /* Write back the result register. */ 29580c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2959b2167459SRichard Henderson 2960b2167459SRichard Henderson /* Write back PSW[CB]. */ 29616fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 29626fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2963b2167459SRichard Henderson 2964f8f5986eSRichard Henderson /* 2965f8f5986eSRichard Henderson * Write back PSW[V] for the division step. 2966f8f5986eSRichard Henderson * Shift cb{8} from where it lives in bit 32 to bit 31, 2967f8f5986eSRichard Henderson * so that it overlaps r2{32} in bit 31. 2968f8f5986eSRichard Henderson */ 2969f8f5986eSRichard Henderson tcg_gen_shri_i64(cpu_psw_v, cpu_psw_cb, 1); 29706fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2971b2167459SRichard Henderson 2972b2167459SRichard Henderson /* Install the new nullification. */ 29730c982a28SRichard Henderson if (a->cf) { 2974f8f5986eSRichard Henderson TCGv_i64 sv = NULL, uv = NULL; 2975b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2976f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, add1, add2, in1, 1, false); 2977f8f5986eSRichard Henderson } else if (cond_need_cb(a->cf >> 1)) { 2978f8f5986eSRichard Henderson uv = do_add_uv(ctx, cpu_psw_cb, NULL, in1, 1, false); 2979b2167459SRichard Henderson } 2980f8f5986eSRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, uv, sv); 2981b2167459SRichard Henderson } 2982b2167459SRichard Henderson 298331234768SRichard Henderson return nullify_end(ctx); 2984b2167459SRichard Henderson } 2985b2167459SRichard Henderson 29860588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2987b2167459SRichard Henderson { 29880588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 29890588e061SRichard Henderson } 29900588e061SRichard Henderson 29910588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 29920588e061SRichard Henderson { 29930588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 29940588e061SRichard Henderson } 29950588e061SRichard Henderson 29960588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 29970588e061SRichard Henderson { 29980588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 29990588e061SRichard Henderson } 30000588e061SRichard Henderson 30010588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 30020588e061SRichard Henderson { 30030588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 30040588e061SRichard Henderson } 30050588e061SRichard Henderson 30060588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 30070588e061SRichard Henderson { 30080588e061SRichard Henderson return do_sub_imm(ctx, a, false); 30090588e061SRichard Henderson } 30100588e061SRichard Henderson 30110588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 30120588e061SRichard Henderson { 30130588e061SRichard Henderson return do_sub_imm(ctx, a, true); 30140588e061SRichard Henderson } 30150588e061SRichard Henderson 3016345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 30170588e061SRichard Henderson { 30186fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 3019b2167459SRichard Henderson 30200588e061SRichard Henderson if (a->cf) { 3021b2167459SRichard Henderson nullify_over(ctx); 3022b2167459SRichard Henderson } 3023b2167459SRichard Henderson 30246fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 30250588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 3026345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 3027b2167459SRichard Henderson 302831234768SRichard Henderson return nullify_end(ctx); 3029b2167459SRichard Henderson } 3030b2167459SRichard Henderson 30310843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 30320843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 30330843563fSRichard Henderson { 30340843563fSRichard Henderson TCGv_i64 r1, r2, dest; 30350843563fSRichard Henderson 30360843563fSRichard Henderson if (!ctx->is_pa20) { 30370843563fSRichard Henderson return false; 30380843563fSRichard Henderson } 30390843563fSRichard Henderson 30400843563fSRichard Henderson nullify_over(ctx); 30410843563fSRichard Henderson 30420843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 30430843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 30440843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 30450843563fSRichard Henderson 30460843563fSRichard Henderson fn(dest, r1, r2); 30470843563fSRichard Henderson save_gpr(ctx, a->t, dest); 30480843563fSRichard Henderson 30490843563fSRichard Henderson return nullify_end(ctx); 30500843563fSRichard Henderson } 30510843563fSRichard Henderson 3052151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 3053151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 3054151f309bSRichard Henderson { 3055151f309bSRichard Henderson TCGv_i64 r, dest; 3056151f309bSRichard Henderson 3057151f309bSRichard Henderson if (!ctx->is_pa20) { 3058151f309bSRichard Henderson return false; 3059151f309bSRichard Henderson } 3060151f309bSRichard Henderson 3061151f309bSRichard Henderson nullify_over(ctx); 3062151f309bSRichard Henderson 3063151f309bSRichard Henderson r = load_gpr(ctx, a->r); 3064151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 3065151f309bSRichard Henderson 3066151f309bSRichard Henderson fn(dest, r, a->i); 3067151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 3068151f309bSRichard Henderson 3069151f309bSRichard Henderson return nullify_end(ctx); 3070151f309bSRichard Henderson } 3071151f309bSRichard Henderson 30723bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 30733bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 30743bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 30753bbb8e48SRichard Henderson { 30763bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 30773bbb8e48SRichard Henderson 30783bbb8e48SRichard Henderson if (!ctx->is_pa20) { 30793bbb8e48SRichard Henderson return false; 30803bbb8e48SRichard Henderson } 30813bbb8e48SRichard Henderson 30823bbb8e48SRichard Henderson nullify_over(ctx); 30833bbb8e48SRichard Henderson 30843bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 30853bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 30863bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 30873bbb8e48SRichard Henderson 30883bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 30893bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 30903bbb8e48SRichard Henderson 30913bbb8e48SRichard Henderson return nullify_end(ctx); 30923bbb8e48SRichard Henderson } 30933bbb8e48SRichard Henderson 30940843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 30950843563fSRichard Henderson { 30960843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 30970843563fSRichard Henderson } 30980843563fSRichard Henderson 30990843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 31000843563fSRichard Henderson { 31010843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 31020843563fSRichard Henderson } 31030843563fSRichard Henderson 31040843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 31050843563fSRichard Henderson { 31060843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 31070843563fSRichard Henderson } 31080843563fSRichard Henderson 31091b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 31101b3cb7c8SRichard Henderson { 31111b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 31121b3cb7c8SRichard Henderson } 31131b3cb7c8SRichard Henderson 3114151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 3115151f309bSRichard Henderson { 3116151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 3117151f309bSRichard Henderson } 3118151f309bSRichard Henderson 3119151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 3120151f309bSRichard Henderson { 3121151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 3122151f309bSRichard Henderson } 3123151f309bSRichard Henderson 3124151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 3125151f309bSRichard Henderson { 3126151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 3127151f309bSRichard Henderson } 3128151f309bSRichard Henderson 31293bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 31303bbb8e48SRichard Henderson { 31313bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 31323bbb8e48SRichard Henderson } 31333bbb8e48SRichard Henderson 31343bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 31353bbb8e48SRichard Henderson { 31363bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 31373bbb8e48SRichard Henderson } 31383bbb8e48SRichard Henderson 313910c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 314010c9e58dSRichard Henderson { 314110c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 314210c9e58dSRichard Henderson } 314310c9e58dSRichard Henderson 314410c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 314510c9e58dSRichard Henderson { 314610c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 314710c9e58dSRichard Henderson } 314810c9e58dSRichard Henderson 314910c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 315010c9e58dSRichard Henderson { 315110c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 315210c9e58dSRichard Henderson } 315310c9e58dSRichard Henderson 3154c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3155c2a7ee3fSRichard Henderson { 3156c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 3157c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3158c2a7ee3fSRichard Henderson 3159c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 3160c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 3161c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 3162c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3163c2a7ee3fSRichard Henderson } 3164c2a7ee3fSRichard Henderson 3165c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 3166c2a7ee3fSRichard Henderson { 3167c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 3168c2a7ee3fSRichard Henderson } 3169c2a7ee3fSRichard Henderson 3170c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3171c2a7ee3fSRichard Henderson { 3172c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 3173c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3174c2a7ee3fSRichard Henderson 3175c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 3176c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 3177c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 3178c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3179c2a7ee3fSRichard Henderson } 3180c2a7ee3fSRichard Henderson 3181c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 3182c2a7ee3fSRichard Henderson { 3183c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 3184c2a7ee3fSRichard Henderson } 3185c2a7ee3fSRichard Henderson 3186c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3187c2a7ee3fSRichard Henderson { 3188c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3189c2a7ee3fSRichard Henderson 3190c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 3191c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 3192c2a7ee3fSRichard Henderson } 3193c2a7ee3fSRichard Henderson 3194c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 3195c2a7ee3fSRichard Henderson { 3196c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 3197c2a7ee3fSRichard Henderson } 3198c2a7ee3fSRichard Henderson 3199c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3200c2a7ee3fSRichard Henderson { 3201c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 3202c2a7ee3fSRichard Henderson } 3203c2a7ee3fSRichard Henderson 3204c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 3205c2a7ee3fSRichard Henderson { 3206c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 3207c2a7ee3fSRichard Henderson } 3208c2a7ee3fSRichard Henderson 32094e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 32104e7abdb1SRichard Henderson { 32114e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 32124e7abdb1SRichard Henderson 32134e7abdb1SRichard Henderson if (!ctx->is_pa20) { 32144e7abdb1SRichard Henderson return false; 32154e7abdb1SRichard Henderson } 32164e7abdb1SRichard Henderson 32174e7abdb1SRichard Henderson nullify_over(ctx); 32184e7abdb1SRichard Henderson 32194e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 32204e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 32214e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 32224e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 32234e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 32244e7abdb1SRichard Henderson 32254e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 32264e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 32274e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 32284e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 32294e7abdb1SRichard Henderson 32304e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 32314e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 32324e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 32334e7abdb1SRichard Henderson 32344e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 32354e7abdb1SRichard Henderson return nullify_end(ctx); 32364e7abdb1SRichard Henderson } 32374e7abdb1SRichard Henderson 32381cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 323996d6407fSRichard Henderson { 3240b5caa17cSRichard Henderson if (ctx->is_pa20) { 3241b5caa17cSRichard Henderson /* 3242b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3243b5caa17cSRichard Henderson * Any base modification still occurs. 3244b5caa17cSRichard Henderson */ 3245b5caa17cSRichard Henderson if (a->t == 0) { 3246b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3247b5caa17cSRichard Henderson } 3248b5caa17cSRichard Henderson } else if (a->size > MO_32) { 32490786a3b6SHelge Deller return gen_illegal(ctx); 3250c53e401eSRichard Henderson } 32511cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 32521cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 325396d6407fSRichard Henderson } 325496d6407fSRichard Henderson 32551cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 325696d6407fSRichard Henderson { 32571cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3258c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 32590786a3b6SHelge Deller return gen_illegal(ctx); 326096d6407fSRichard Henderson } 3261c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 32620786a3b6SHelge Deller } 326396d6407fSRichard Henderson 32641cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 326596d6407fSRichard Henderson { 3266b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3267a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 32686fd0c7bcSRichard Henderson TCGv_i64 addr; 326996d6407fSRichard Henderson 3270c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 327151416c4eSRichard Henderson return gen_illegal(ctx); 327251416c4eSRichard Henderson } 327351416c4eSRichard Henderson 327496d6407fSRichard Henderson nullify_over(ctx); 327596d6407fSRichard Henderson 32761cd012a5SRichard Henderson if (a->m) { 327786f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 327886f8d05fSRichard Henderson we see the result of the load. */ 3279aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 328096d6407fSRichard Henderson } else { 32811cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 328296d6407fSRichard Henderson } 328396d6407fSRichard Henderson 3284c3ea1996SSven Schnelle form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? 3 : 0, 328517fe594cSRichard Henderson a->disp, a->sp, a->m, MMU_DISABLED(ctx)); 3286b1af755cSRichard Henderson 3287b1af755cSRichard Henderson /* 3288b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3289b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3290b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3291b1af755cSRichard Henderson * 3292b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3293b1af755cSRichard Henderson * with the ,co completer. 3294b1af755cSRichard Henderson */ 3295b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3296b1af755cSRichard Henderson 3297a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3298b1af755cSRichard Henderson 32991cd012a5SRichard Henderson if (a->m) { 33001cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 330196d6407fSRichard Henderson } 33021cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 330396d6407fSRichard Henderson 330431234768SRichard Henderson return nullify_end(ctx); 330596d6407fSRichard Henderson } 330696d6407fSRichard Henderson 33071cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 330896d6407fSRichard Henderson { 33096fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 33106fd0c7bcSRichard Henderson TCGv_i64 addr; 331196d6407fSRichard Henderson 331296d6407fSRichard Henderson nullify_over(ctx); 331396d6407fSRichard Henderson 33141cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 331517fe594cSRichard Henderson MMU_DISABLED(ctx)); 33161cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 33171cd012a5SRichard Henderson if (a->a) { 3318f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3319ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3320f9f46db4SEmilio G. Cota } else { 3321ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3322f9f46db4SEmilio G. Cota } 3323f9f46db4SEmilio G. Cota } else { 3324f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3325ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 332696d6407fSRichard Henderson } else { 3327ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 332896d6407fSRichard Henderson } 3329f9f46db4SEmilio G. Cota } 33301cd012a5SRichard Henderson if (a->m) { 33316fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 33321cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 333396d6407fSRichard Henderson } 333496d6407fSRichard Henderson 333531234768SRichard Henderson return nullify_end(ctx); 333696d6407fSRichard Henderson } 333796d6407fSRichard Henderson 333825460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 333925460fc5SRichard Henderson { 33406fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 33416fd0c7bcSRichard Henderson TCGv_i64 addr; 334225460fc5SRichard Henderson 334325460fc5SRichard Henderson if (!ctx->is_pa20) { 334425460fc5SRichard Henderson return false; 334525460fc5SRichard Henderson } 334625460fc5SRichard Henderson nullify_over(ctx); 334725460fc5SRichard Henderson 334825460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 334917fe594cSRichard Henderson MMU_DISABLED(ctx)); 335025460fc5SRichard Henderson val = load_gpr(ctx, a->r); 335125460fc5SRichard Henderson if (a->a) { 335225460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 335325460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 335425460fc5SRichard Henderson } else { 335525460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 335625460fc5SRichard Henderson } 335725460fc5SRichard Henderson } else { 335825460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 335925460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 336025460fc5SRichard Henderson } else { 336125460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 336225460fc5SRichard Henderson } 336325460fc5SRichard Henderson } 336425460fc5SRichard Henderson if (a->m) { 33656fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 336625460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 336725460fc5SRichard Henderson } 336825460fc5SRichard Henderson 336925460fc5SRichard Henderson return nullify_end(ctx); 337025460fc5SRichard Henderson } 337125460fc5SRichard Henderson 33721cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3373d0a851ccSRichard Henderson { 3374d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3375d0a851ccSRichard Henderson 3376d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3377451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 33781cd012a5SRichard Henderson trans_ld(ctx, a); 3379d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 338031234768SRichard Henderson return true; 3381d0a851ccSRichard Henderson } 3382d0a851ccSRichard Henderson 33831cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3384d0a851ccSRichard Henderson { 3385d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3386d0a851ccSRichard Henderson 3387d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3388451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 33891cd012a5SRichard Henderson trans_st(ctx, a); 3390d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 339131234768SRichard Henderson return true; 3392d0a851ccSRichard Henderson } 339395412a61SRichard Henderson 33940588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3395b2167459SRichard Henderson { 33966fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3397b2167459SRichard Henderson 33986fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 33990588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3400b2167459SRichard Henderson cond_free(&ctx->null_cond); 340131234768SRichard Henderson return true; 3402b2167459SRichard Henderson } 3403b2167459SRichard Henderson 34040588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3405b2167459SRichard Henderson { 34066fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 34076fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3408b2167459SRichard Henderson 34096fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3410b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3411b2167459SRichard Henderson cond_free(&ctx->null_cond); 341231234768SRichard Henderson return true; 3413b2167459SRichard Henderson } 3414b2167459SRichard Henderson 34150588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3416b2167459SRichard Henderson { 34176fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3418b2167459SRichard Henderson 3419b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3420d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 34210588e061SRichard Henderson if (a->b == 0) { 34226fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3423b2167459SRichard Henderson } else { 34246fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3425b2167459SRichard Henderson } 34260588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3427b2167459SRichard Henderson cond_free(&ctx->null_cond); 342831234768SRichard Henderson return true; 3429b2167459SRichard Henderson } 3430b2167459SRichard Henderson 34316fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3432e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 343398cd9ca7SRichard Henderson { 34346fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 343598cd9ca7SRichard Henderson DisasCond cond; 343698cd9ca7SRichard Henderson 343798cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3438aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 343998cd9ca7SRichard Henderson 34406fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 344198cd9ca7SRichard Henderson 3442f764718dSRichard Henderson sv = NULL; 3443b47a4a02SSven Schnelle if (cond_need_sv(c)) { 344498cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 344598cd9ca7SRichard Henderson } 344698cd9ca7SRichard Henderson 34474fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 344801afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 344998cd9ca7SRichard Henderson } 345098cd9ca7SRichard Henderson 345101afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 345298cd9ca7SRichard Henderson { 3453e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3454e9efd4bcSRichard Henderson return false; 3455e9efd4bcSRichard Henderson } 345601afb7beSRichard Henderson nullify_over(ctx); 3457e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3458e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 345901afb7beSRichard Henderson } 346001afb7beSRichard Henderson 346101afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 346201afb7beSRichard Henderson { 3463c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3464c65c3ee1SRichard Henderson return false; 3465c65c3ee1SRichard Henderson } 346601afb7beSRichard Henderson nullify_over(ctx); 34676fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3468c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 346901afb7beSRichard Henderson } 347001afb7beSRichard Henderson 34716fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 347201afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 347301afb7beSRichard Henderson { 34746fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 347598cd9ca7SRichard Henderson DisasCond cond; 3476bdcccc17SRichard Henderson bool d = false; 347798cd9ca7SRichard Henderson 3478f25d3160SRichard Henderson /* 3479f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3480f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3481f25d3160SRichard Henderson */ 3482f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3483f25d3160SRichard Henderson d = c >= 5; 3484f25d3160SRichard Henderson if (d) { 3485f25d3160SRichard Henderson c &= 3; 3486f25d3160SRichard Henderson } 3487f25d3160SRichard Henderson } 3488f25d3160SRichard Henderson 348998cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3490aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3491f764718dSRichard Henderson sv = NULL; 3492bdcccc17SRichard Henderson cb_cond = NULL; 349398cd9ca7SRichard Henderson 3494b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3495aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3496aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3497bdcccc17SRichard Henderson 34986fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 34996fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 35006fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 35016fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3502bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3503b47a4a02SSven Schnelle } else { 35046fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3505b47a4a02SSven Schnelle } 3506b47a4a02SSven Schnelle if (cond_need_sv(c)) { 3507f8f5986eSRichard Henderson sv = do_add_sv(ctx, dest, in1, in2, in1, 0, d); 350898cd9ca7SRichard Henderson } 350998cd9ca7SRichard Henderson 3510a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 351143675d20SSven Schnelle save_gpr(ctx, r, dest); 351201afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 351398cd9ca7SRichard Henderson } 351498cd9ca7SRichard Henderson 351501afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 351698cd9ca7SRichard Henderson { 351701afb7beSRichard Henderson nullify_over(ctx); 351801afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 351901afb7beSRichard Henderson } 352001afb7beSRichard Henderson 352101afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 352201afb7beSRichard Henderson { 352301afb7beSRichard Henderson nullify_over(ctx); 35246fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 352501afb7beSRichard Henderson } 352601afb7beSRichard Henderson 352701afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 352801afb7beSRichard Henderson { 35296fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 353098cd9ca7SRichard Henderson DisasCond cond; 353198cd9ca7SRichard Henderson 353298cd9ca7SRichard Henderson nullify_over(ctx); 353398cd9ca7SRichard Henderson 3534aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 353501afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 353682d0c831SRichard Henderson if (a->d) { 353782d0c831SRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 353882d0c831SRichard Henderson } else { 35391e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 35406fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 35416fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 35421e9ab9fbSRichard Henderson } 354398cd9ca7SRichard Henderson 35441e9ab9fbSRichard Henderson cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 354501afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 354698cd9ca7SRichard Henderson } 354798cd9ca7SRichard Henderson 354801afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 354998cd9ca7SRichard Henderson { 35506fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 355101afb7beSRichard Henderson DisasCond cond; 35521e9ab9fbSRichard Henderson int p; 355301afb7beSRichard Henderson 355401afb7beSRichard Henderson nullify_over(ctx); 355501afb7beSRichard Henderson 3556aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 355701afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 355882d0c831SRichard Henderson p = a->p | (a->d ? 0 : 32); 35596fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, tcg_r, p); 356001afb7beSRichard Henderson 356101afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 356201afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 356301afb7beSRichard Henderson } 356401afb7beSRichard Henderson 356501afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 356601afb7beSRichard Henderson { 35676fd0c7bcSRichard Henderson TCGv_i64 dest; 356898cd9ca7SRichard Henderson DisasCond cond; 356998cd9ca7SRichard Henderson 357098cd9ca7SRichard Henderson nullify_over(ctx); 357198cd9ca7SRichard Henderson 357201afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 357301afb7beSRichard Henderson if (a->r1 == 0) { 35746fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 357598cd9ca7SRichard Henderson } else { 35766fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 357798cd9ca7SRichard Henderson } 357898cd9ca7SRichard Henderson 35794fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 35804fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 358101afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 358201afb7beSRichard Henderson } 358301afb7beSRichard Henderson 358401afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 358501afb7beSRichard Henderson { 35866fd0c7bcSRichard Henderson TCGv_i64 dest; 358701afb7beSRichard Henderson DisasCond cond; 358801afb7beSRichard Henderson 358901afb7beSRichard Henderson nullify_over(ctx); 359001afb7beSRichard Henderson 359101afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 35926fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 359301afb7beSRichard Henderson 35944fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 35954fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 359601afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 359798cd9ca7SRichard Henderson } 359898cd9ca7SRichard Henderson 3599f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 36000b1347d2SRichard Henderson { 36016fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 36020b1347d2SRichard Henderson 3603f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3604f7b775a9SRichard Henderson return false; 3605f7b775a9SRichard Henderson } 360630878590SRichard Henderson if (a->c) { 36070b1347d2SRichard Henderson nullify_over(ctx); 36080b1347d2SRichard Henderson } 36090b1347d2SRichard Henderson 361030878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3611f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 361230878590SRichard Henderson if (a->r1 == 0) { 3613f7b775a9SRichard Henderson if (a->d) { 36146fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3615f7b775a9SRichard Henderson } else { 3616aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3617f7b775a9SRichard Henderson 36186fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 36196fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 36206fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3621f7b775a9SRichard Henderson } 362230878590SRichard Henderson } else if (a->r1 == a->r2) { 3623f7b775a9SRichard Henderson if (a->d) { 36246fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3625f7b775a9SRichard Henderson } else { 36260b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3627e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3628e1d635e8SRichard Henderson 36296fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 36306fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3631f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3632e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 36336fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3634f7b775a9SRichard Henderson } 3635f7b775a9SRichard Henderson } else { 36366fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3637f7b775a9SRichard Henderson 3638f7b775a9SRichard Henderson if (a->d) { 3639aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3640aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3641f7b775a9SRichard Henderson 36426fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 3643a01491a2SHelge Deller tcg_gen_shl_i64(t, src1, n); 36446fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 3645a01491a2SHelge Deller tcg_gen_shr_i64(dest, src2, cpu_sar); 36466fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 36470b1347d2SRichard Henderson } else { 36480b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 36490b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 36500b1347d2SRichard Henderson 36516fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3652967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3653967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 36540b1347d2SRichard Henderson } 3655f7b775a9SRichard Henderson } 365630878590SRichard Henderson save_gpr(ctx, a->t, dest); 36570b1347d2SRichard Henderson 36580b1347d2SRichard Henderson /* Install the new nullification. */ 36590b1347d2SRichard Henderson cond_free(&ctx->null_cond); 366030878590SRichard Henderson if (a->c) { 3661d37fad0aSSven Schnelle ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36620b1347d2SRichard Henderson } 366331234768SRichard Henderson return nullify_end(ctx); 36640b1347d2SRichard Henderson } 36650b1347d2SRichard Henderson 3666f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 36670b1347d2SRichard Henderson { 3668f7b775a9SRichard Henderson unsigned width, sa; 36696fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 36700b1347d2SRichard Henderson 3671f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3672f7b775a9SRichard Henderson return false; 3673f7b775a9SRichard Henderson } 367430878590SRichard Henderson if (a->c) { 36750b1347d2SRichard Henderson nullify_over(ctx); 36760b1347d2SRichard Henderson } 36770b1347d2SRichard Henderson 3678f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3679f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3680f7b775a9SRichard Henderson 368130878590SRichard Henderson dest = dest_gpr(ctx, a->t); 368230878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 368305bfd4dbSRichard Henderson if (a->r1 == 0) { 36846fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3685c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 36866fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3687f7b775a9SRichard Henderson } else { 3688f7b775a9SRichard Henderson assert(!a->d); 3689f7b775a9SRichard Henderson if (a->r1 == a->r2) { 36900b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 36916fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 36920b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 36936fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 36940b1347d2SRichard Henderson } else { 3695967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3696967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 36970b1347d2SRichard Henderson } 3698f7b775a9SRichard Henderson } 369930878590SRichard Henderson save_gpr(ctx, a->t, dest); 37000b1347d2SRichard Henderson 37010b1347d2SRichard Henderson /* Install the new nullification. */ 37020b1347d2SRichard Henderson cond_free(&ctx->null_cond); 370330878590SRichard Henderson if (a->c) { 3704d37fad0aSSven Schnelle ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37050b1347d2SRichard Henderson } 370631234768SRichard Henderson return nullify_end(ctx); 37070b1347d2SRichard Henderson } 37080b1347d2SRichard Henderson 3709bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 37100b1347d2SRichard Henderson { 3711bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 37126fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 37130b1347d2SRichard Henderson 3714bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3715bd792da3SRichard Henderson return false; 3716bd792da3SRichard Henderson } 371730878590SRichard Henderson if (a->c) { 37180b1347d2SRichard Henderson nullify_over(ctx); 37190b1347d2SRichard Henderson } 37200b1347d2SRichard Henderson 372130878590SRichard Henderson dest = dest_gpr(ctx, a->t); 372230878590SRichard Henderson src = load_gpr(ctx, a->r); 3723aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37240b1347d2SRichard Henderson 37250b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 37266fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 37276fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3728d781cb77SRichard Henderson 372930878590SRichard Henderson if (a->se) { 3730bd792da3SRichard Henderson if (!a->d) { 37316fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3732bd792da3SRichard Henderson src = dest; 3733bd792da3SRichard Henderson } 37346fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 37356fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 37360b1347d2SRichard Henderson } else { 3737bd792da3SRichard Henderson if (!a->d) { 37386fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3739bd792da3SRichard Henderson src = dest; 3740bd792da3SRichard Henderson } 37416fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 37426fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 37430b1347d2SRichard Henderson } 374430878590SRichard Henderson save_gpr(ctx, a->t, dest); 37450b1347d2SRichard Henderson 37460b1347d2SRichard Henderson /* Install the new nullification. */ 37470b1347d2SRichard Henderson cond_free(&ctx->null_cond); 374830878590SRichard Henderson if (a->c) { 3749bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37500b1347d2SRichard Henderson } 375131234768SRichard Henderson return nullify_end(ctx); 37520b1347d2SRichard Henderson } 37530b1347d2SRichard Henderson 3754bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 37550b1347d2SRichard Henderson { 3756bd792da3SRichard Henderson unsigned len, cpos, width; 37576fd0c7bcSRichard Henderson TCGv_i64 dest, src; 37580b1347d2SRichard Henderson 3759bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3760bd792da3SRichard Henderson return false; 3761bd792da3SRichard Henderson } 376230878590SRichard Henderson if (a->c) { 37630b1347d2SRichard Henderson nullify_over(ctx); 37640b1347d2SRichard Henderson } 37650b1347d2SRichard Henderson 3766bd792da3SRichard Henderson len = a->len; 3767bd792da3SRichard Henderson width = a->d ? 64 : 32; 3768bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3769bd792da3SRichard Henderson if (cpos + len > width) { 3770bd792da3SRichard Henderson len = width - cpos; 3771bd792da3SRichard Henderson } 3772bd792da3SRichard Henderson 377330878590SRichard Henderson dest = dest_gpr(ctx, a->t); 377430878590SRichard Henderson src = load_gpr(ctx, a->r); 377530878590SRichard Henderson if (a->se) { 37766fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 37770b1347d2SRichard Henderson } else { 37786fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 37790b1347d2SRichard Henderson } 378030878590SRichard Henderson save_gpr(ctx, a->t, dest); 37810b1347d2SRichard Henderson 37820b1347d2SRichard Henderson /* Install the new nullification. */ 37830b1347d2SRichard Henderson cond_free(&ctx->null_cond); 378430878590SRichard Henderson if (a->c) { 3785bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 37860b1347d2SRichard Henderson } 378731234768SRichard Henderson return nullify_end(ctx); 37880b1347d2SRichard Henderson } 37890b1347d2SRichard Henderson 379072ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 37910b1347d2SRichard Henderson { 379272ae4f2bSRichard Henderson unsigned len, width; 3793c53e401eSRichard Henderson uint64_t mask0, mask1; 37946fd0c7bcSRichard Henderson TCGv_i64 dest; 37950b1347d2SRichard Henderson 379672ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 379772ae4f2bSRichard Henderson return false; 379872ae4f2bSRichard Henderson } 379930878590SRichard Henderson if (a->c) { 38000b1347d2SRichard Henderson nullify_over(ctx); 38010b1347d2SRichard Henderson } 380272ae4f2bSRichard Henderson 380372ae4f2bSRichard Henderson len = a->len; 380472ae4f2bSRichard Henderson width = a->d ? 64 : 32; 380572ae4f2bSRichard Henderson if (a->cpos + len > width) { 380672ae4f2bSRichard Henderson len = width - a->cpos; 38070b1347d2SRichard Henderson } 38080b1347d2SRichard Henderson 380930878590SRichard Henderson dest = dest_gpr(ctx, a->t); 381030878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 381130878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 38120b1347d2SRichard Henderson 381330878590SRichard Henderson if (a->nz) { 38146fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 38156fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 38166fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 38170b1347d2SRichard Henderson } else { 38186fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 38190b1347d2SRichard Henderson } 382030878590SRichard Henderson save_gpr(ctx, a->t, dest); 38210b1347d2SRichard Henderson 38220b1347d2SRichard Henderson /* Install the new nullification. */ 38230b1347d2SRichard Henderson cond_free(&ctx->null_cond); 382430878590SRichard Henderson if (a->c) { 382572ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 38260b1347d2SRichard Henderson } 382731234768SRichard Henderson return nullify_end(ctx); 38280b1347d2SRichard Henderson } 38290b1347d2SRichard Henderson 383072ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 38310b1347d2SRichard Henderson { 383230878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 383372ae4f2bSRichard Henderson unsigned len, width; 38346fd0c7bcSRichard Henderson TCGv_i64 dest, val; 38350b1347d2SRichard Henderson 383672ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 383772ae4f2bSRichard Henderson return false; 383872ae4f2bSRichard Henderson } 383930878590SRichard Henderson if (a->c) { 38400b1347d2SRichard Henderson nullify_over(ctx); 38410b1347d2SRichard Henderson } 384272ae4f2bSRichard Henderson 384372ae4f2bSRichard Henderson len = a->len; 384472ae4f2bSRichard Henderson width = a->d ? 64 : 32; 384572ae4f2bSRichard Henderson if (a->cpos + len > width) { 384672ae4f2bSRichard Henderson len = width - a->cpos; 38470b1347d2SRichard Henderson } 38480b1347d2SRichard Henderson 384930878590SRichard Henderson dest = dest_gpr(ctx, a->t); 385030878590SRichard Henderson val = load_gpr(ctx, a->r); 38510b1347d2SRichard Henderson if (rs == 0) { 38526fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 38530b1347d2SRichard Henderson } else { 38546fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 38550b1347d2SRichard Henderson } 385630878590SRichard Henderson save_gpr(ctx, a->t, dest); 38570b1347d2SRichard Henderson 38580b1347d2SRichard Henderson /* Install the new nullification. */ 38590b1347d2SRichard Henderson cond_free(&ctx->null_cond); 386030878590SRichard Henderson if (a->c) { 386172ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 38620b1347d2SRichard Henderson } 386331234768SRichard Henderson return nullify_end(ctx); 38640b1347d2SRichard Henderson } 38650b1347d2SRichard Henderson 386672ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 38676fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 38680b1347d2SRichard Henderson { 38690b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 387072ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 38716fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3872c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 38730b1347d2SRichard Henderson 38740b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3875aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3876aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 38770b1347d2SRichard Henderson 38780b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 38796fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 38806fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 38810b1347d2SRichard Henderson 3882aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 38836fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 38846fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 38850b1347d2SRichard Henderson if (rs) { 38866fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 38876fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 38886fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 38896fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 38900b1347d2SRichard Henderson } else { 38916fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 38920b1347d2SRichard Henderson } 38930b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 38940b1347d2SRichard Henderson 38950b1347d2SRichard Henderson /* Install the new nullification. */ 38960b1347d2SRichard Henderson cond_free(&ctx->null_cond); 38970b1347d2SRichard Henderson if (c) { 389872ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 38990b1347d2SRichard Henderson } 390031234768SRichard Henderson return nullify_end(ctx); 39010b1347d2SRichard Henderson } 39020b1347d2SRichard Henderson 390372ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 390430878590SRichard Henderson { 390572ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 390672ae4f2bSRichard Henderson return false; 390772ae4f2bSRichard Henderson } 3908a6deecceSSven Schnelle if (a->c) { 3909a6deecceSSven Schnelle nullify_over(ctx); 3910a6deecceSSven Schnelle } 391172ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 391272ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 391330878590SRichard Henderson } 391430878590SRichard Henderson 391572ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 391630878590SRichard Henderson { 391772ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 391872ae4f2bSRichard Henderson return false; 391972ae4f2bSRichard Henderson } 3920a6deecceSSven Schnelle if (a->c) { 3921a6deecceSSven Schnelle nullify_over(ctx); 3922a6deecceSSven Schnelle } 392372ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 39246fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 392530878590SRichard Henderson } 39260b1347d2SRichard Henderson 39278340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 392898cd9ca7SRichard Henderson { 3929019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY 3930*bc921866SRichard Henderson ctx->iaq_j.space = tcg_temp_new_i64(); 3931*bc921866SRichard Henderson load_spr(ctx, ctx->iaq_j.space, a->sp); 3932c301f34eSRichard Henderson #endif 3933019f4159SRichard Henderson 3934*bc921866SRichard Henderson ctx->iaq_j.base = tcg_temp_new_i64(); 3935*bc921866SRichard Henderson ctx->iaq_j.disp = 0; 3936*bc921866SRichard Henderson 3937*bc921866SRichard Henderson tcg_gen_addi_i64(ctx->iaq_j.base, load_gpr(ctx, a->b), a->disp); 3938*bc921866SRichard Henderson ctx->iaq_j.base = do_ibranch_priv(ctx, ctx->iaq_j.base); 3939*bc921866SRichard Henderson 3940*bc921866SRichard Henderson return do_ibranch(ctx, a->l, true, a->n); 394198cd9ca7SRichard Henderson } 394298cd9ca7SRichard Henderson 39438340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 394498cd9ca7SRichard Henderson { 39452644f80bSRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 394698cd9ca7SRichard Henderson } 394798cd9ca7SRichard Henderson 39488340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 394943e05652SRichard Henderson { 3950*bc921866SRichard Henderson int64_t disp = a->disp; 395143e05652SRichard Henderson 39526e5f5300SSven Schnelle nullify_over(ctx); 39536e5f5300SSven Schnelle 395443e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 395543e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 395643e05652SRichard Henderson * expensive to track. Real hardware will trap for 395743e05652SRichard Henderson * b gateway 395843e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 395943e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 396043e05652SRichard Henderson * diagnose the security hole 396143e05652SRichard Henderson * b gateway 396243e05652SRichard Henderson * b evil 396343e05652SRichard Henderson * in which instructions at evil would run with increased privs. 396443e05652SRichard Henderson */ 3965*bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 396643e05652SRichard Henderson return gen_illegal(ctx); 396743e05652SRichard Henderson } 396843e05652SRichard Henderson 396943e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 397043e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 397194956d7bSPhilippe Mathieu-Daudé int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next); 397243e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 397343e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 397443e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 397543e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 397643e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 397743e05652SRichard Henderson if (type < 0) { 397831234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 397931234768SRichard Henderson return true; 398043e05652SRichard Henderson } 398143e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 398243e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 3983*bc921866SRichard Henderson disp -= ctx->privilege; 3984*bc921866SRichard Henderson disp += type - 4; 398543e05652SRichard Henderson } 398643e05652SRichard Henderson } else { 3987*bc921866SRichard Henderson disp -= ctx->privilege; /* priv = 0 */ 398843e05652SRichard Henderson } 398943e05652SRichard Henderson #endif 399043e05652SRichard Henderson 39916e5f5300SSven Schnelle if (a->l) { 39926fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 39936e5f5300SSven Schnelle if (ctx->privilege < 3) { 39946fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 39956e5f5300SSven Schnelle } 39966fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 39976e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 39986e5f5300SSven Schnelle } 39996e5f5300SSven Schnelle 4000*bc921866SRichard Henderson return do_dbranch(ctx, disp, 0, a->n); 400143e05652SRichard Henderson } 400243e05652SRichard Henderson 40038340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 400498cd9ca7SRichard Henderson { 4005b35aec85SRichard Henderson if (a->x) { 4006*bc921866SRichard Henderson DisasIAQE next = iaqe_incr(&ctx->iaq_f, 8); 4007*bc921866SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 4008*bc921866SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 4009*bc921866SRichard Henderson 4010660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 4011*bc921866SRichard Henderson copy_iaoq_entry(ctx, t0, &next); 4012*bc921866SRichard Henderson tcg_gen_shli_i64(t1, load_gpr(ctx, a->x), 3); 4013*bc921866SRichard Henderson tcg_gen_add_i64(t0, t0, t1); 4014*bc921866SRichard Henderson 4015*bc921866SRichard Henderson ctx->iaq_j = iaqe_next_absv(ctx, t0); 4016*bc921866SRichard Henderson return do_ibranch(ctx, a->l, false, a->n); 4017b35aec85SRichard Henderson } else { 4018b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 40192644f80bSRichard Henderson return do_dbranch(ctx, 0, a->l, a->n); 4020b35aec85SRichard Henderson } 402198cd9ca7SRichard Henderson } 402298cd9ca7SRichard Henderson 40238340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 402498cd9ca7SRichard Henderson { 40256fd0c7bcSRichard Henderson TCGv_i64 dest; 402698cd9ca7SRichard Henderson 40278340f534SRichard Henderson if (a->x == 0) { 40288340f534SRichard Henderson dest = load_gpr(ctx, a->b); 402998cd9ca7SRichard Henderson } else { 4030aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 40316fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 40326fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 403398cd9ca7SRichard Henderson } 4034660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 4035*bc921866SRichard Henderson ctx->iaq_j = iaqe_next_absv(ctx, dest); 4036*bc921866SRichard Henderson 4037*bc921866SRichard Henderson return do_ibranch(ctx, 0, false, a->n); 403898cd9ca7SRichard Henderson } 403998cd9ca7SRichard Henderson 40408340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 404198cd9ca7SRichard Henderson { 4042019f4159SRichard Henderson TCGv_i64 b = load_gpr(ctx, a->b); 404398cd9ca7SRichard Henderson 4044019f4159SRichard Henderson #ifndef CONFIG_USER_ONLY 4045*bc921866SRichard Henderson ctx->iaq_j.space = space_select(ctx, 0, b); 4046c301f34eSRichard Henderson #endif 4047*bc921866SRichard Henderson ctx->iaq_j.base = do_ibranch_priv(ctx, b); 4048*bc921866SRichard Henderson ctx->iaq_j.disp = 0; 4049019f4159SRichard Henderson 4050*bc921866SRichard Henderson return do_ibranch(ctx, a->l, false, a->n); 405198cd9ca7SRichard Henderson } 405298cd9ca7SRichard Henderson 4053a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 4054a8966ba7SRichard Henderson { 4055a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 4056a8966ba7SRichard Henderson return ctx->is_pa20; 4057a8966ba7SRichard Henderson } 4058a8966ba7SRichard Henderson 40591ca74648SRichard Henderson /* 40601ca74648SRichard Henderson * Float class 0 40611ca74648SRichard Henderson */ 4062ebe9383cSRichard Henderson 40631ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4064ebe9383cSRichard Henderson { 4065ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 4066ebe9383cSRichard Henderson } 4067ebe9383cSRichard Henderson 406859f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 406959f8c04bSHelge Deller { 4070a300dad3SRichard Henderson uint64_t ret; 4071a300dad3SRichard Henderson 4072c53e401eSRichard Henderson if (ctx->is_pa20) { 4073a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 4074a300dad3SRichard Henderson } else { 4075a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 4076a300dad3SRichard Henderson } 4077a300dad3SRichard Henderson 407859f8c04bSHelge Deller nullify_over(ctx); 4079a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 408059f8c04bSHelge Deller return nullify_end(ctx); 408159f8c04bSHelge Deller } 408259f8c04bSHelge Deller 40831ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 40841ca74648SRichard Henderson { 40851ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 40861ca74648SRichard Henderson } 40871ca74648SRichard Henderson 4088ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4089ebe9383cSRichard Henderson { 4090ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 4091ebe9383cSRichard Henderson } 4092ebe9383cSRichard Henderson 40931ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 40941ca74648SRichard Henderson { 40951ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 40961ca74648SRichard Henderson } 40971ca74648SRichard Henderson 40981ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4099ebe9383cSRichard Henderson { 4100ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 4101ebe9383cSRichard Henderson } 4102ebe9383cSRichard Henderson 41031ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 41041ca74648SRichard Henderson { 41051ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 41061ca74648SRichard Henderson } 41071ca74648SRichard Henderson 4108ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4109ebe9383cSRichard Henderson { 4110ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 4111ebe9383cSRichard Henderson } 4112ebe9383cSRichard Henderson 41131ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 41141ca74648SRichard Henderson { 41151ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 41161ca74648SRichard Henderson } 41171ca74648SRichard Henderson 41181ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 41191ca74648SRichard Henderson { 41201ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 41211ca74648SRichard Henderson } 41221ca74648SRichard Henderson 41231ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 41241ca74648SRichard Henderson { 41251ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 41261ca74648SRichard Henderson } 41271ca74648SRichard Henderson 41281ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 41291ca74648SRichard Henderson { 41301ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 41311ca74648SRichard Henderson } 41321ca74648SRichard Henderson 41331ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 41341ca74648SRichard Henderson { 41351ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 41361ca74648SRichard Henderson } 41371ca74648SRichard Henderson 41381ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4139ebe9383cSRichard Henderson { 4140ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 4141ebe9383cSRichard Henderson } 4142ebe9383cSRichard Henderson 41431ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 41441ca74648SRichard Henderson { 41451ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 41461ca74648SRichard Henderson } 41471ca74648SRichard Henderson 4148ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4149ebe9383cSRichard Henderson { 4150ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 4151ebe9383cSRichard Henderson } 4152ebe9383cSRichard Henderson 41531ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 41541ca74648SRichard Henderson { 41551ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 41561ca74648SRichard Henderson } 41571ca74648SRichard Henderson 41581ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4159ebe9383cSRichard Henderson { 4160ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 4161ebe9383cSRichard Henderson } 4162ebe9383cSRichard Henderson 41631ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 41641ca74648SRichard Henderson { 41651ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 41661ca74648SRichard Henderson } 41671ca74648SRichard Henderson 4168ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4169ebe9383cSRichard Henderson { 4170ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4171ebe9383cSRichard Henderson } 4172ebe9383cSRichard Henderson 41731ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 41741ca74648SRichard Henderson { 41751ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 41761ca74648SRichard Henderson } 41771ca74648SRichard Henderson 41781ca74648SRichard Henderson /* 41791ca74648SRichard Henderson * Float class 1 41801ca74648SRichard Henderson */ 41811ca74648SRichard Henderson 41821ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 41831ca74648SRichard Henderson { 41841ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 41851ca74648SRichard Henderson } 41861ca74648SRichard Henderson 41871ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 41881ca74648SRichard Henderson { 41891ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 41901ca74648SRichard Henderson } 41911ca74648SRichard Henderson 41921ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 41931ca74648SRichard Henderson { 41941ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 41951ca74648SRichard Henderson } 41961ca74648SRichard Henderson 41971ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 41981ca74648SRichard Henderson { 41991ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 42001ca74648SRichard Henderson } 42011ca74648SRichard Henderson 42021ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 42031ca74648SRichard Henderson { 42041ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 42051ca74648SRichard Henderson } 42061ca74648SRichard Henderson 42071ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 42081ca74648SRichard Henderson { 42091ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 42101ca74648SRichard Henderson } 42111ca74648SRichard Henderson 42121ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 42131ca74648SRichard Henderson { 42141ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 42151ca74648SRichard Henderson } 42161ca74648SRichard Henderson 42171ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 42181ca74648SRichard Henderson { 42191ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 42201ca74648SRichard Henderson } 42211ca74648SRichard Henderson 42221ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 42231ca74648SRichard Henderson { 42241ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 42251ca74648SRichard Henderson } 42261ca74648SRichard Henderson 42271ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 42281ca74648SRichard Henderson { 42291ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 42301ca74648SRichard Henderson } 42311ca74648SRichard Henderson 42321ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 42331ca74648SRichard Henderson { 42341ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 42351ca74648SRichard Henderson } 42361ca74648SRichard Henderson 42371ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 42381ca74648SRichard Henderson { 42391ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 42401ca74648SRichard Henderson } 42411ca74648SRichard Henderson 42421ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 42431ca74648SRichard Henderson { 42441ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 42451ca74648SRichard Henderson } 42461ca74648SRichard Henderson 42471ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 42481ca74648SRichard Henderson { 42491ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 42501ca74648SRichard Henderson } 42511ca74648SRichard Henderson 42521ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 42531ca74648SRichard Henderson { 42541ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 42551ca74648SRichard Henderson } 42561ca74648SRichard Henderson 42571ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 42581ca74648SRichard Henderson { 42591ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 42601ca74648SRichard Henderson } 42611ca74648SRichard Henderson 42621ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 42631ca74648SRichard Henderson { 42641ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 42651ca74648SRichard Henderson } 42661ca74648SRichard Henderson 42671ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 42681ca74648SRichard Henderson { 42691ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 42701ca74648SRichard Henderson } 42711ca74648SRichard Henderson 42721ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 42731ca74648SRichard Henderson { 42741ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 42751ca74648SRichard Henderson } 42761ca74648SRichard Henderson 42771ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 42781ca74648SRichard Henderson { 42791ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 42801ca74648SRichard Henderson } 42811ca74648SRichard Henderson 42821ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 42831ca74648SRichard Henderson { 42841ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 42851ca74648SRichard Henderson } 42861ca74648SRichard Henderson 42871ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 42881ca74648SRichard Henderson { 42891ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 42901ca74648SRichard Henderson } 42911ca74648SRichard Henderson 42921ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 42931ca74648SRichard Henderson { 42941ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 42951ca74648SRichard Henderson } 42961ca74648SRichard Henderson 42971ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 42981ca74648SRichard Henderson { 42991ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 43001ca74648SRichard Henderson } 43011ca74648SRichard Henderson 43021ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 43031ca74648SRichard Henderson { 43041ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 43051ca74648SRichard Henderson } 43061ca74648SRichard Henderson 43071ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 43081ca74648SRichard Henderson { 43091ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 43101ca74648SRichard Henderson } 43111ca74648SRichard Henderson 43121ca74648SRichard Henderson /* 43131ca74648SRichard Henderson * Float class 2 43141ca74648SRichard Henderson */ 43151ca74648SRichard Henderson 43161ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4317ebe9383cSRichard Henderson { 4318ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4319ebe9383cSRichard Henderson 4320ebe9383cSRichard Henderson nullify_over(ctx); 4321ebe9383cSRichard Henderson 43221ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 43231ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 432429dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 432529dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4326ebe9383cSRichard Henderson 4327ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4328ebe9383cSRichard Henderson 43291ca74648SRichard Henderson return nullify_end(ctx); 4330ebe9383cSRichard Henderson } 4331ebe9383cSRichard Henderson 43321ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4333ebe9383cSRichard Henderson { 4334ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4335ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4336ebe9383cSRichard Henderson 4337ebe9383cSRichard Henderson nullify_over(ctx); 4338ebe9383cSRichard Henderson 43391ca74648SRichard Henderson ta = load_frd0(a->r1); 43401ca74648SRichard Henderson tb = load_frd0(a->r2); 434129dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 434229dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4343ebe9383cSRichard Henderson 4344ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4345ebe9383cSRichard Henderson 434631234768SRichard Henderson return nullify_end(ctx); 4347ebe9383cSRichard Henderson } 4348ebe9383cSRichard Henderson 43491ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4350ebe9383cSRichard Henderson { 43516fd0c7bcSRichard Henderson TCGv_i64 t; 4352ebe9383cSRichard Henderson 4353ebe9383cSRichard Henderson nullify_over(ctx); 4354ebe9383cSRichard Henderson 4355aac0f603SRichard Henderson t = tcg_temp_new_i64(); 43566fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4357ebe9383cSRichard Henderson 43581ca74648SRichard Henderson if (a->y == 1) { 4359ebe9383cSRichard Henderson int mask; 4360ebe9383cSRichard Henderson bool inv = false; 4361ebe9383cSRichard Henderson 43621ca74648SRichard Henderson switch (a->c) { 4363ebe9383cSRichard Henderson case 0: /* simple */ 43646fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 4365ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4366ebe9383cSRichard Henderson goto done; 4367ebe9383cSRichard Henderson case 2: /* rej */ 4368ebe9383cSRichard Henderson inv = true; 4369ebe9383cSRichard Henderson /* fallthru */ 4370ebe9383cSRichard Henderson case 1: /* acc */ 4371ebe9383cSRichard Henderson mask = 0x43ff800; 4372ebe9383cSRichard Henderson break; 4373ebe9383cSRichard Henderson case 6: /* rej8 */ 4374ebe9383cSRichard Henderson inv = true; 4375ebe9383cSRichard Henderson /* fallthru */ 4376ebe9383cSRichard Henderson case 5: /* acc8 */ 4377ebe9383cSRichard Henderson mask = 0x43f8000; 4378ebe9383cSRichard Henderson break; 4379ebe9383cSRichard Henderson case 9: /* acc6 */ 4380ebe9383cSRichard Henderson mask = 0x43e0000; 4381ebe9383cSRichard Henderson break; 4382ebe9383cSRichard Henderson case 13: /* acc4 */ 4383ebe9383cSRichard Henderson mask = 0x4380000; 4384ebe9383cSRichard Henderson break; 4385ebe9383cSRichard Henderson case 17: /* acc2 */ 4386ebe9383cSRichard Henderson mask = 0x4200000; 4387ebe9383cSRichard Henderson break; 4388ebe9383cSRichard Henderson default: 43891ca74648SRichard Henderson gen_illegal(ctx); 43901ca74648SRichard Henderson return true; 4391ebe9383cSRichard Henderson } 4392ebe9383cSRichard Henderson if (inv) { 43936fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 43946fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 4395ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 4396ebe9383cSRichard Henderson } else { 43976fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 4398ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 4399ebe9383cSRichard Henderson } 44001ca74648SRichard Henderson } else { 44011ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 44021ca74648SRichard Henderson 44036fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 44041ca74648SRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 44051ca74648SRichard Henderson } 44061ca74648SRichard Henderson 4407ebe9383cSRichard Henderson done: 440831234768SRichard Henderson return nullify_end(ctx); 4409ebe9383cSRichard Henderson } 4410ebe9383cSRichard Henderson 44111ca74648SRichard Henderson /* 44121ca74648SRichard Henderson * Float class 2 44131ca74648SRichard Henderson */ 44141ca74648SRichard Henderson 44151ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4416ebe9383cSRichard Henderson { 44171ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 44181ca74648SRichard Henderson } 44191ca74648SRichard Henderson 44201ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 44211ca74648SRichard Henderson { 44221ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 44231ca74648SRichard Henderson } 44241ca74648SRichard Henderson 44251ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 44261ca74648SRichard Henderson { 44271ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 44281ca74648SRichard Henderson } 44291ca74648SRichard Henderson 44301ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 44311ca74648SRichard Henderson { 44321ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 44331ca74648SRichard Henderson } 44341ca74648SRichard Henderson 44351ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 44361ca74648SRichard Henderson { 44371ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 44381ca74648SRichard Henderson } 44391ca74648SRichard Henderson 44401ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 44411ca74648SRichard Henderson { 44421ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 44431ca74648SRichard Henderson } 44441ca74648SRichard Henderson 44451ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 44461ca74648SRichard Henderson { 44471ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 44481ca74648SRichard Henderson } 44491ca74648SRichard Henderson 44501ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 44511ca74648SRichard Henderson { 44521ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 44531ca74648SRichard Henderson } 44541ca74648SRichard Henderson 44551ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 44561ca74648SRichard Henderson { 44571ca74648SRichard Henderson TCGv_i64 x, y; 4458ebe9383cSRichard Henderson 4459ebe9383cSRichard Henderson nullify_over(ctx); 4460ebe9383cSRichard Henderson 44611ca74648SRichard Henderson x = load_frw0_i64(a->r1); 44621ca74648SRichard Henderson y = load_frw0_i64(a->r2); 44631ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 44641ca74648SRichard Henderson save_frd(a->t, x); 4465ebe9383cSRichard Henderson 446631234768SRichard Henderson return nullify_end(ctx); 4467ebe9383cSRichard Henderson } 4468ebe9383cSRichard Henderson 4469ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4470ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4471ebe9383cSRichard Henderson { 4472ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4473ebe9383cSRichard Henderson } 4474ebe9383cSRichard Henderson 4475b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4476ebe9383cSRichard Henderson { 4477b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4478b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4479b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4480b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4481b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4482ebe9383cSRichard Henderson 4483ebe9383cSRichard Henderson nullify_over(ctx); 4484ebe9383cSRichard Henderson 4485ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4486ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4487ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4488ebe9383cSRichard Henderson 448931234768SRichard Henderson return nullify_end(ctx); 4490ebe9383cSRichard Henderson } 4491ebe9383cSRichard Henderson 4492b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4493b1e2af57SRichard Henderson { 4494b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4495b1e2af57SRichard Henderson } 4496b1e2af57SRichard Henderson 4497b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4498b1e2af57SRichard Henderson { 4499b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4500b1e2af57SRichard Henderson } 4501b1e2af57SRichard Henderson 4502b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4503b1e2af57SRichard Henderson { 4504b1e2af57SRichard Henderson nullify_over(ctx); 4505b1e2af57SRichard Henderson 4506b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4507b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4508b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4509b1e2af57SRichard Henderson 4510b1e2af57SRichard Henderson return nullify_end(ctx); 4511b1e2af57SRichard Henderson } 4512b1e2af57SRichard Henderson 4513b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4514b1e2af57SRichard Henderson { 4515b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4516b1e2af57SRichard Henderson } 4517b1e2af57SRichard Henderson 4518b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4519b1e2af57SRichard Henderson { 4520b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4521b1e2af57SRichard Henderson } 4522b1e2af57SRichard Henderson 4523c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4524ebe9383cSRichard Henderson { 4525c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4526ebe9383cSRichard Henderson 4527ebe9383cSRichard Henderson nullify_over(ctx); 4528c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4529c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4530c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4531ebe9383cSRichard Henderson 4532c3bad4f8SRichard Henderson if (a->neg) { 4533ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4534ebe9383cSRichard Henderson } else { 4535ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4536ebe9383cSRichard Henderson } 4537ebe9383cSRichard Henderson 4538c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 453931234768SRichard Henderson return nullify_end(ctx); 4540ebe9383cSRichard Henderson } 4541ebe9383cSRichard Henderson 4542c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4543ebe9383cSRichard Henderson { 4544c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4545ebe9383cSRichard Henderson 4546ebe9383cSRichard Henderson nullify_over(ctx); 4547c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4548c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4549c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4550ebe9383cSRichard Henderson 4551c3bad4f8SRichard Henderson if (a->neg) { 4552ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4553ebe9383cSRichard Henderson } else { 4554ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4555ebe9383cSRichard Henderson } 4556ebe9383cSRichard Henderson 4557c3bad4f8SRichard Henderson save_frd(a->t, x); 455831234768SRichard Henderson return nullify_end(ctx); 4559ebe9383cSRichard Henderson } 4560ebe9383cSRichard Henderson 456138193127SRichard Henderson /* Emulate PDC BTLB, called by SeaBIOS-hppa */ 456238193127SRichard Henderson static bool trans_diag_btlb(DisasContext *ctx, arg_diag_btlb *a) 456315da177bSSven Schnelle { 4564cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4565cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4566ad75a51eSRichard Henderson nullify_over(ctx); 4567ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4568cf6b28d4SHelge Deller return nullify_end(ctx); 456938193127SRichard Henderson #endif 457015da177bSSven Schnelle } 457138193127SRichard Henderson 457238193127SRichard Henderson /* Print char in %r26 to first serial console, used by SeaBIOS-hppa */ 457338193127SRichard Henderson static bool trans_diag_cout(DisasContext *ctx, arg_diag_cout *a) 457438193127SRichard Henderson { 457538193127SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 457638193127SRichard Henderson #ifndef CONFIG_USER_ONLY 4577dbca0835SHelge Deller nullify_over(ctx); 4578dbca0835SHelge Deller gen_helper_diag_console_output(tcg_env); 4579dbca0835SHelge Deller return nullify_end(ctx); 4580ad75a51eSRichard Henderson #endif 458138193127SRichard Henderson } 458238193127SRichard Henderson 45833bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa1(DisasContext *ctx, arg_empty *a) 45843bdf2081SHelge Deller { 45853bdf2081SHelge Deller return !ctx->is_pa20 && do_getshadowregs(ctx); 45863bdf2081SHelge Deller } 45873bdf2081SHelge Deller 45883bdf2081SHelge Deller static bool trans_diag_getshadowregs_pa2(DisasContext *ctx, arg_empty *a) 45893bdf2081SHelge Deller { 45903bdf2081SHelge Deller return ctx->is_pa20 && do_getshadowregs(ctx); 45913bdf2081SHelge Deller } 45923bdf2081SHelge Deller 45933bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa1(DisasContext *ctx, arg_empty *a) 45943bdf2081SHelge Deller { 45953bdf2081SHelge Deller return !ctx->is_pa20 && do_putshadowregs(ctx); 45963bdf2081SHelge Deller } 45973bdf2081SHelge Deller 45983bdf2081SHelge Deller static bool trans_diag_putshadowregs_pa2(DisasContext *ctx, arg_empty *a) 45993bdf2081SHelge Deller { 46003bdf2081SHelge Deller return ctx->is_pa20 && do_putshadowregs(ctx); 46013bdf2081SHelge Deller } 46023bdf2081SHelge Deller 460338193127SRichard Henderson static bool trans_diag_unimp(DisasContext *ctx, arg_diag_unimp *a) 460438193127SRichard Henderson { 460538193127SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4606ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4607ad75a51eSRichard Henderson return true; 4608ad75a51eSRichard Henderson } 460915da177bSSven Schnelle 4610b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 461161766fe9SRichard Henderson { 461251b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4613f764718dSRichard Henderson int bound; 461461766fe9SRichard Henderson 461551b061fbSRichard Henderson ctx->cs = cs; 4616494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4617bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 46183d68ee7bSRichard Henderson 46193d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4620c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 46213d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 4622*bc921866SRichard Henderson ctx->iaq_f.disp = ctx->base.pc_first | ctx->privilege; 4623*bc921866SRichard Henderson ctx->iaq_b.disp = ctx->base.tb->cs_base | ctx->privilege; 4624217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4625c301f34eSRichard Henderson #else 4626494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4627bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4628bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4629451d993dSRichard Henderson : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX); 46303d68ee7bSRichard Henderson 4631c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4632c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4633c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4634c301f34eSRichard Henderson int32_t diff = cs_base; 4635c301f34eSRichard Henderson 4636*bc921866SRichard Henderson ctx->iaq_f.disp = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4637*bc921866SRichard Henderson if (diff) { 4638*bc921866SRichard Henderson ctx->iaq_b.disp = ctx->iaq_f.disp + diff; 4639*bc921866SRichard Henderson } else { 4640*bc921866SRichard Henderson ctx->iaq_b.base = cpu_iaoq_b; 4641*bc921866SRichard Henderson ctx->iaq_b.space = cpu_iasq_b; 4642*bc921866SRichard Henderson } 4643c301f34eSRichard Henderson #endif 464461766fe9SRichard Henderson 4645a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4646a4db4a78SRichard Henderson 46473d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 46483d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4649b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 465061766fe9SRichard Henderson } 465161766fe9SRichard Henderson 465251b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 465351b061fbSRichard Henderson { 465451b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 465561766fe9SRichard Henderson 46563d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 465751b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 465851b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4659494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 466051b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 466151b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4662129e9cc3SRichard Henderson } 466351b061fbSRichard Henderson ctx->null_lab = NULL; 466461766fe9SRichard Henderson } 466561766fe9SRichard Henderson 466651b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 466751b061fbSRichard Henderson { 466851b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 466951b061fbSRichard Henderson 4670*bc921866SRichard Henderson tcg_debug_assert(!iaqe_variable(&ctx->iaq_f)); 4671*bc921866SRichard Henderson tcg_gen_insn_start(ctx->iaq_f.disp, 4672*bc921866SRichard Henderson iaqe_variable(&ctx->iaq_b) ? -1 : ctx->iaq_b.disp, 4673*bc921866SRichard Henderson 0); 467424638bd1SRichard Henderson ctx->insn_start_updated = false; 467551b061fbSRichard Henderson } 467651b061fbSRichard Henderson 467751b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 467851b061fbSRichard Henderson { 467951b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4680b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 468151b061fbSRichard Henderson DisasJumpType ret; 468251b061fbSRichard Henderson 468351b061fbSRichard Henderson /* Execute one insn. */ 4684ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4685c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 468631234768SRichard Henderson do_page_zero(ctx); 468731234768SRichard Henderson ret = ctx->base.is_jmp; 4688869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4689ba1d0b44SRichard Henderson } else 4690ba1d0b44SRichard Henderson #endif 4691ba1d0b44SRichard Henderson { 469261766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 469361766fe9SRichard Henderson the page permissions for execute. */ 46944e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 469561766fe9SRichard Henderson 4696*bc921866SRichard Henderson /* 4697*bc921866SRichard Henderson * Set up the IA queue for the next insn. 4698*bc921866SRichard Henderson * This will be overwritten by a branch. 4699*bc921866SRichard Henderson */ 4700*bc921866SRichard Henderson ctx->iaq_n = NULL; 4701*bc921866SRichard Henderson memset(&ctx->iaq_j, 0, sizeof(ctx->iaq_j)); 470261766fe9SRichard Henderson 470351b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 470451b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4705869051eaSRichard Henderson ret = DISAS_NEXT; 4706129e9cc3SRichard Henderson } else { 47071a19da0dSRichard Henderson ctx->insn = insn; 470831274b46SRichard Henderson if (!decode(ctx, insn)) { 470931274b46SRichard Henderson gen_illegal(ctx); 471031274b46SRichard Henderson } 471131234768SRichard Henderson ret = ctx->base.is_jmp; 471251b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4713129e9cc3SRichard Henderson } 471461766fe9SRichard Henderson } 471561766fe9SRichard Henderson 4716dbdccbdfSRichard Henderson /* If the TranslationBlock must end, do so. */ 4717dbdccbdfSRichard Henderson ctx->base.pc_next += 4; 4718dbdccbdfSRichard Henderson if (ret != DISAS_NEXT) { 4719dbdccbdfSRichard Henderson return; 472061766fe9SRichard Henderson } 4721dbdccbdfSRichard Henderson /* Note this also detects a priority change. */ 4722*bc921866SRichard Henderson if (iaqe_variable(&ctx->iaq_b) 4723*bc921866SRichard Henderson || ctx->iaq_b.disp != ctx->iaq_f.disp + 4) { 4724dbdccbdfSRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 4725dbdccbdfSRichard Henderson return; 4726129e9cc3SRichard Henderson } 4727dbdccbdfSRichard Henderson 4728dbdccbdfSRichard Henderson /* 4729dbdccbdfSRichard Henderson * Advance the insn queue. 4730dbdccbdfSRichard Henderson * The only exit now is DISAS_TOO_MANY from the translator loop. 4731dbdccbdfSRichard Henderson */ 4732*bc921866SRichard Henderson ctx->iaq_f.disp = ctx->iaq_b.disp; 4733*bc921866SRichard Henderson if (!ctx->iaq_n) { 4734*bc921866SRichard Henderson ctx->iaq_b.disp += 4; 4735*bc921866SRichard Henderson return; 4736*bc921866SRichard Henderson } 4737*bc921866SRichard Henderson /* 4738*bc921866SRichard Henderson * If IAQ_Next is variable in any way, we need to copy into the 4739*bc921866SRichard Henderson * IAQ_Back globals, in case the next insn raises an exception. 4740*bc921866SRichard Henderson */ 4741*bc921866SRichard Henderson if (ctx->iaq_n->base) { 4742*bc921866SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaq_n); 4743*bc921866SRichard Henderson ctx->iaq_b.base = cpu_iaoq_b; 4744*bc921866SRichard Henderson ctx->iaq_b.disp = 0; 47450dcd6640SRichard Henderson } else { 4746*bc921866SRichard Henderson ctx->iaq_b.disp = ctx->iaq_n->disp; 47470dcd6640SRichard Henderson } 4748*bc921866SRichard Henderson if (ctx->iaq_n->space) { 4749*bc921866SRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, ctx->iaq_n->space); 4750*bc921866SRichard Henderson ctx->iaq_b.space = cpu_iasq_b; 4751142faf5fSRichard Henderson } 475261766fe9SRichard Henderson } 475361766fe9SRichard Henderson 475451b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 475551b061fbSRichard Henderson { 475651b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4757e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 4758dbdccbdfSRichard Henderson /* Assume the insn queue has not been advanced. */ 4759*bc921866SRichard Henderson DisasIAQE *f = &ctx->iaq_b; 4760*bc921866SRichard Henderson DisasIAQE *b = ctx->iaq_n; 476151b061fbSRichard Henderson 4762e1b5a5edSRichard Henderson switch (is_jmp) { 4763869051eaSRichard Henderson case DISAS_NORETURN: 476461766fe9SRichard Henderson break; 476551b061fbSRichard Henderson case DISAS_TOO_MANY: 4766dbdccbdfSRichard Henderson /* The insn queue has not been advanced. */ 4767*bc921866SRichard Henderson f = &ctx->iaq_f; 4768*bc921866SRichard Henderson b = &ctx->iaq_b; 476961766fe9SRichard Henderson /* FALLTHRU */ 4770dbdccbdfSRichard Henderson case DISAS_IAQ_N_STALE: 4771*bc921866SRichard Henderson if (use_goto_tb(ctx, f, b) 4772dbdccbdfSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4773dbdccbdfSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 4774dbdccbdfSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 4775*bc921866SRichard Henderson gen_goto_tb(ctx, 0, f, b); 47768532a14eSRichard Henderson break; 477761766fe9SRichard Henderson } 4778c5d0aec2SRichard Henderson /* FALLTHRU */ 4779dbdccbdfSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4780*bc921866SRichard Henderson install_iaq_entries(ctx, f, b); 4781dbdccbdfSRichard Henderson nullify_save(ctx); 4782dbdccbdfSRichard Henderson if (is_jmp == DISAS_IAQ_N_STALE_EXIT) { 4783dbdccbdfSRichard Henderson tcg_gen_exit_tb(NULL, 0); 4784dbdccbdfSRichard Henderson break; 4785dbdccbdfSRichard Henderson } 4786dbdccbdfSRichard Henderson /* FALLTHRU */ 4787dbdccbdfSRichard Henderson case DISAS_IAQ_N_UPDATED: 4788dbdccbdfSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 4789dbdccbdfSRichard Henderson break; 4790c5d0aec2SRichard Henderson case DISAS_EXIT: 4791c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 479261766fe9SRichard Henderson break; 479361766fe9SRichard Henderson default: 479451b061fbSRichard Henderson g_assert_not_reached(); 479561766fe9SRichard Henderson } 479651b061fbSRichard Henderson } 479761766fe9SRichard Henderson 47988eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 47998eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 480051b061fbSRichard Henderson { 4801c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 480261766fe9SRichard Henderson 4803ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4804ba1d0b44SRichard Henderson switch (pc) { 48057ad439dfSRichard Henderson case 0x00: 48068eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4807ba1d0b44SRichard Henderson return; 48087ad439dfSRichard Henderson case 0xb0: 48098eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4810ba1d0b44SRichard Henderson return; 48117ad439dfSRichard Henderson case 0xe0: 48128eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4813ba1d0b44SRichard Henderson return; 48147ad439dfSRichard Henderson case 0x100: 48158eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4816ba1d0b44SRichard Henderson return; 48177ad439dfSRichard Henderson } 4818ba1d0b44SRichard Henderson #endif 4819ba1d0b44SRichard Henderson 48208eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 48218eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 482261766fe9SRichard Henderson } 482351b061fbSRichard Henderson 482451b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 482551b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 482651b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 482751b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 482851b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 482951b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 483051b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 483151b061fbSRichard Henderson }; 483251b061fbSRichard Henderson 4833597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 483432f0c394SAnton Johansson vaddr pc, void *host_pc) 483551b061fbSRichard Henderson { 4836*bc921866SRichard Henderson DisasContext ctx = { }; 4837306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 483861766fe9SRichard Henderson } 4839