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" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 260843563fSRichard Henderson #include "tcg/tcg-op-gvec.h" 2761766fe9SRichard Henderson #include "exec/helper-proto.h" 2861766fe9SRichard Henderson #include "exec/helper-gen.h" 29869051eaSRichard Henderson #include "exec/translator.h" 3061766fe9SRichard Henderson #include "exec/log.h" 3161766fe9SRichard Henderson 32d53106c9SRichard Henderson #define HELPER_H "helper.h" 33d53106c9SRichard Henderson #include "exec/helper-info.c.inc" 34d53106c9SRichard Henderson #undef HELPER_H 35d53106c9SRichard Henderson 36aac0f603SRichard Henderson /* Choose to use explicit sizes within this file. */ 37aac0f603SRichard Henderson #undef tcg_temp_new 38d53106c9SRichard Henderson 3961766fe9SRichard Henderson typedef struct DisasCond { 4061766fe9SRichard Henderson TCGCond c; 416fd0c7bcSRichard Henderson TCGv_i64 a0, a1; 4261766fe9SRichard Henderson } DisasCond; 4361766fe9SRichard Henderson 4461766fe9SRichard Henderson typedef struct DisasContext { 45d01a3625SRichard Henderson DisasContextBase base; 4661766fe9SRichard Henderson CPUState *cs; 47f5b5c857SRichard Henderson TCGOp *insn_start; 4861766fe9SRichard Henderson 49c53e401eSRichard Henderson uint64_t iaoq_f; 50c53e401eSRichard Henderson uint64_t iaoq_b; 51c53e401eSRichard Henderson uint64_t iaoq_n; 526fd0c7bcSRichard Henderson TCGv_i64 iaoq_n_var; 5361766fe9SRichard Henderson 5461766fe9SRichard Henderson DisasCond null_cond; 5561766fe9SRichard Henderson TCGLabel *null_lab; 5661766fe9SRichard Henderson 57a4db4a78SRichard Henderson TCGv_i64 zero; 58a4db4a78SRichard Henderson 591a19da0dSRichard Henderson uint32_t insn; 60494737b7SRichard Henderson uint32_t tb_flags; 613d68ee7bSRichard Henderson int mmu_idx; 623d68ee7bSRichard Henderson int privilege; 6361766fe9SRichard Henderson bool psw_n_nonzero; 64bd6243a3SRichard Henderson bool is_pa20; 65217d1a5eSRichard Henderson 66217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 67217d1a5eSRichard Henderson MemOp unalign; 68217d1a5eSRichard Henderson #endif 6961766fe9SRichard Henderson } DisasContext; 7061766fe9SRichard Henderson 71217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 72217d1a5eSRichard Henderson #define UNALIGN(C) (C)->unalign 7317fe594cSRichard Henderson #define MMU_DISABLED(C) false 74217d1a5eSRichard Henderson #else 752d4afb03SRichard Henderson #define UNALIGN(C) MO_ALIGN 7617fe594cSRichard Henderson #define MMU_DISABLED(C) MMU_IDX_MMU_DISABLED((C)->mmu_idx) 77217d1a5eSRichard Henderson #endif 78217d1a5eSRichard Henderson 79e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 80451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val) 81e36f27efSRichard Henderson { 82881d1073SHelge Deller /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */ 83881d1073SHelge Deller if (ctx->is_pa20) { 84e36f27efSRichard Henderson if (val & PSW_SM_W) { 85881d1073SHelge Deller val |= PSW_W; 86881d1073SHelge Deller } 87881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_G); 88881d1073SHelge Deller } else { 89881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_O); 90e36f27efSRichard Henderson } 91e36f27efSRichard Henderson return val; 92e36f27efSRichard Henderson } 93e36f27efSRichard Henderson 94deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base. */ 95451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val) 96deee69a1SRichard Henderson { 97deee69a1SRichard Henderson return ~val; 98deee69a1SRichard Henderson } 99deee69a1SRichard Henderson 1001cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value 1011cd012a5SRichard Henderson we use for the final M. */ 102451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val) 1031cd012a5SRichard Henderson { 1041cd012a5SRichard Henderson return val & 2 ? (val & 1 ? -1 : 1) : 0; 1051cd012a5SRichard Henderson } 1061cd012a5SRichard Henderson 107740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify. */ 108451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val) 109740038d7SRichard Henderson { 110740038d7SRichard Henderson return val ? 1 : -1; 111740038d7SRichard Henderson } 112740038d7SRichard Henderson 113451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val) 114740038d7SRichard Henderson { 115740038d7SRichard Henderson return val ? -1 : 1; 116740038d7SRichard Henderson } 117740038d7SRichard Henderson 118740038d7SRichard Henderson /* Used for branch targets and fp memory ops. */ 119451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val) 12001afb7beSRichard Henderson { 12101afb7beSRichard Henderson return val << 2; 12201afb7beSRichard Henderson } 12301afb7beSRichard Henderson 124740038d7SRichard Henderson /* Used for fp memory ops. */ 125451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val) 126740038d7SRichard Henderson { 127740038d7SRichard Henderson return val << 3; 128740038d7SRichard Henderson } 129740038d7SRichard Henderson 1300588e061SRichard Henderson /* Used for assemble_21. */ 131451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val) 1320588e061SRichard Henderson { 1330588e061SRichard Henderson return val << 11; 1340588e061SRichard Henderson } 1350588e061SRichard Henderson 13672ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val) 13772ae4f2bSRichard Henderson { 13872ae4f2bSRichard Henderson /* 13972ae4f2bSRichard Henderson * Officially, 32 * x + 32 - y. 14072ae4f2bSRichard Henderson * Here, x is already in bit 5, and y is [4:0]. 14172ae4f2bSRichard Henderson * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1, 14272ae4f2bSRichard Henderson * with the overflow from bit 4 summing with x. 14372ae4f2bSRichard Henderson */ 14472ae4f2bSRichard Henderson return (val ^ 31) + 1; 14572ae4f2bSRichard Henderson } 14672ae4f2bSRichard Henderson 147*72bace2dSRichard Henderson /* Expander for assemble_16(s,im14). */ 148*72bace2dSRichard Henderson static int expand_16(DisasContext *ctx, int val) 149*72bace2dSRichard Henderson { 150*72bace2dSRichard Henderson /* 151*72bace2dSRichard Henderson * @val is bits [0:15], containing both im14 and s. 152*72bace2dSRichard Henderson * Swizzle thing around depending on PSW.W. 153*72bace2dSRichard Henderson */ 154*72bace2dSRichard Henderson int s = extract32(val, 14, 2); 155*72bace2dSRichard Henderson int i = (-(val & 1) << 13) | extract32(val, 1, 13); 156*72bace2dSRichard Henderson 157*72bace2dSRichard Henderson if (ctx->tb_flags & PSW_W) { 158*72bace2dSRichard Henderson i ^= s << 13; 159*72bace2dSRichard Henderson } 160*72bace2dSRichard Henderson return i; 161*72bace2dSRichard Henderson } 162*72bace2dSRichard Henderson 163*72bace2dSRichard Henderson /* The sp field is only present with !PSW_W. */ 164*72bace2dSRichard Henderson static int sp0_if_wide(DisasContext *ctx, int sp) 165*72bace2dSRichard Henderson { 166*72bace2dSRichard Henderson return ctx->tb_flags & PSW_W ? 0 : sp; 167*72bace2dSRichard Henderson } 168*72bace2dSRichard Henderson 169c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */ 170c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val) 171c65c3ee1SRichard Henderson { 172c65c3ee1SRichard Henderson return val ? val : 4; /* 0 == "*<<" */ 173c65c3ee1SRichard Henderson } 174c65c3ee1SRichard Henderson 17501afb7beSRichard Henderson 17640f9f908SRichard Henderson /* Include the auto-generated decoder. */ 177abff1abfSPaolo Bonzini #include "decode-insns.c.inc" 17840f9f908SRichard Henderson 17961766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 18061766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 181869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 18261766fe9SRichard Henderson 18361766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 18461766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 185869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 18661766fe9SRichard Henderson 187e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 188e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 189e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 190c5d0aec2SRichard Henderson #define DISAS_EXIT DISAS_TARGET_3 191e1b5a5edSRichard Henderson 19261766fe9SRichard Henderson /* global register indexes */ 1936fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32]; 19433423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 195494737b7SRichard Henderson static TCGv_i64 cpu_srH; 1966fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f; 1976fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b; 198c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 199c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 2006fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar; 2016fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n; 2026fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v; 2036fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb; 2046fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb; 20561766fe9SRichard Henderson 20661766fe9SRichard Henderson void hppa_translate_init(void) 20761766fe9SRichard Henderson { 20861766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 20961766fe9SRichard Henderson 2106fd0c7bcSRichard Henderson typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 21161766fe9SRichard Henderson static const GlobalVar vars[] = { 21235136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 21361766fe9SRichard Henderson DEF_VAR(psw_n), 21461766fe9SRichard Henderson DEF_VAR(psw_v), 21561766fe9SRichard Henderson DEF_VAR(psw_cb), 21661766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 21761766fe9SRichard Henderson DEF_VAR(iaoq_f), 21861766fe9SRichard Henderson DEF_VAR(iaoq_b), 21961766fe9SRichard Henderson }; 22061766fe9SRichard Henderson 22161766fe9SRichard Henderson #undef DEF_VAR 22261766fe9SRichard Henderson 22361766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 22461766fe9SRichard Henderson static const char gr_names[32][4] = { 22561766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 22661766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 22761766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 22861766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 22961766fe9SRichard Henderson }; 23033423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 231494737b7SRichard Henderson static const char sr_names[5][4] = { 232494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 23333423472SRichard Henderson }; 23461766fe9SRichard Henderson 23561766fe9SRichard Henderson int i; 23661766fe9SRichard Henderson 237f764718dSRichard Henderson cpu_gr[0] = NULL; 23861766fe9SRichard Henderson for (i = 1; i < 32; i++) { 239ad75a51eSRichard Henderson cpu_gr[i] = tcg_global_mem_new(tcg_env, 24061766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 24161766fe9SRichard Henderson gr_names[i]); 24261766fe9SRichard Henderson } 24333423472SRichard Henderson for (i = 0; i < 4; i++) { 244ad75a51eSRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 24533423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 24633423472SRichard Henderson sr_names[i]); 24733423472SRichard Henderson } 248ad75a51eSRichard Henderson cpu_srH = tcg_global_mem_new_i64(tcg_env, 249494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 250494737b7SRichard Henderson sr_names[4]); 25161766fe9SRichard Henderson 25261766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 25361766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 254ad75a51eSRichard Henderson *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 25561766fe9SRichard Henderson } 256c301f34eSRichard Henderson 257ad75a51eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 258c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 259c301f34eSRichard Henderson "iasq_f"); 260ad75a51eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 261c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 262c301f34eSRichard Henderson "iasq_b"); 26361766fe9SRichard Henderson } 26461766fe9SRichard Henderson 265f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg) 266f5b5c857SRichard Henderson { 267f5b5c857SRichard Henderson assert(ctx->insn_start != NULL); 268f5b5c857SRichard Henderson tcg_set_insn_start_param(ctx->insn_start, 2, breg); 269f5b5c857SRichard Henderson ctx->insn_start = NULL; 270f5b5c857SRichard Henderson } 271f5b5c857SRichard Henderson 272129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 273129e9cc3SRichard Henderson { 274f764718dSRichard Henderson return (DisasCond){ 275f764718dSRichard Henderson .c = TCG_COND_NEVER, 276f764718dSRichard Henderson .a0 = NULL, 277f764718dSRichard Henderson .a1 = NULL, 278f764718dSRichard Henderson }; 279129e9cc3SRichard Henderson } 280129e9cc3SRichard Henderson 281df0232feSRichard Henderson static DisasCond cond_make_t(void) 282df0232feSRichard Henderson { 283df0232feSRichard Henderson return (DisasCond){ 284df0232feSRichard Henderson .c = TCG_COND_ALWAYS, 285df0232feSRichard Henderson .a0 = NULL, 286df0232feSRichard Henderson .a1 = NULL, 287df0232feSRichard Henderson }; 288df0232feSRichard Henderson } 289df0232feSRichard Henderson 290129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 291129e9cc3SRichard Henderson { 292f764718dSRichard Henderson return (DisasCond){ 293f764718dSRichard Henderson .c = TCG_COND_NE, 294f764718dSRichard Henderson .a0 = cpu_psw_n, 2956fd0c7bcSRichard Henderson .a1 = tcg_constant_i64(0) 296f764718dSRichard Henderson }; 297129e9cc3SRichard Henderson } 298129e9cc3SRichard Henderson 2996fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 300b47a4a02SSven Schnelle { 301b47a4a02SSven Schnelle assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 3024fe9533aSRichard Henderson return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 3034fe9533aSRichard Henderson } 3044fe9533aSRichard Henderson 3056fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0) 3064fe9533aSRichard Henderson { 3076fd0c7bcSRichard Henderson return cond_make_tmp(c, a0, tcg_constant_i64(0)); 308b47a4a02SSven Schnelle } 309b47a4a02SSven Schnelle 3106fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0) 311129e9cc3SRichard Henderson { 312aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3136fd0c7bcSRichard Henderson tcg_gen_mov_i64(tmp, a0); 314b47a4a02SSven Schnelle return cond_make_0_tmp(c, tmp); 315129e9cc3SRichard Henderson } 316129e9cc3SRichard Henderson 3176fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 318129e9cc3SRichard Henderson { 319aac0f603SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 320aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 321129e9cc3SRichard Henderson 3226fd0c7bcSRichard Henderson tcg_gen_mov_i64(t0, a0); 3236fd0c7bcSRichard Henderson tcg_gen_mov_i64(t1, a1); 3244fe9533aSRichard Henderson return cond_make_tmp(c, t0, t1); 325129e9cc3SRichard Henderson } 326129e9cc3SRichard Henderson 327129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 328129e9cc3SRichard Henderson { 329129e9cc3SRichard Henderson switch (cond->c) { 330129e9cc3SRichard Henderson default: 331f764718dSRichard Henderson cond->a0 = NULL; 332f764718dSRichard Henderson cond->a1 = NULL; 333129e9cc3SRichard Henderson /* fallthru */ 334129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 335129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 336129e9cc3SRichard Henderson break; 337129e9cc3SRichard Henderson case TCG_COND_NEVER: 338129e9cc3SRichard Henderson break; 339129e9cc3SRichard Henderson } 340129e9cc3SRichard Henderson } 341129e9cc3SRichard Henderson 3426fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 34361766fe9SRichard Henderson { 34461766fe9SRichard Henderson if (reg == 0) { 345bc3da3cfSRichard Henderson return ctx->zero; 34661766fe9SRichard Henderson } else { 34761766fe9SRichard Henderson return cpu_gr[reg]; 34861766fe9SRichard Henderson } 34961766fe9SRichard Henderson } 35061766fe9SRichard Henderson 3516fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 35261766fe9SRichard Henderson { 353129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 354aac0f603SRichard Henderson return tcg_temp_new_i64(); 35561766fe9SRichard Henderson } else { 35661766fe9SRichard Henderson return cpu_gr[reg]; 35761766fe9SRichard Henderson } 35861766fe9SRichard Henderson } 35961766fe9SRichard Henderson 3606fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 361129e9cc3SRichard Henderson { 362129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 3636fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 364129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 365129e9cc3SRichard Henderson } else { 3666fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 367129e9cc3SRichard Henderson } 368129e9cc3SRichard Henderson } 369129e9cc3SRichard Henderson 3706fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 371129e9cc3SRichard Henderson { 372129e9cc3SRichard Henderson if (reg != 0) { 373129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 374129e9cc3SRichard Henderson } 375129e9cc3SRichard Henderson } 376129e9cc3SRichard Henderson 377e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 37896d6407fSRichard Henderson # define HI_OFS 0 37996d6407fSRichard Henderson # define LO_OFS 4 38096d6407fSRichard Henderson #else 38196d6407fSRichard Henderson # define HI_OFS 4 38296d6407fSRichard Henderson # define LO_OFS 0 38396d6407fSRichard Henderson #endif 38496d6407fSRichard Henderson 38596d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 38696d6407fSRichard Henderson { 38796d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 388ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 38996d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 39096d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 39196d6407fSRichard Henderson return ret; 39296d6407fSRichard Henderson } 39396d6407fSRichard Henderson 394ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 395ebe9383cSRichard Henderson { 396ebe9383cSRichard Henderson if (rt == 0) { 3970992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 3980992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 3990992a930SRichard Henderson return ret; 400ebe9383cSRichard Henderson } else { 401ebe9383cSRichard Henderson return load_frw_i32(rt); 402ebe9383cSRichard Henderson } 403ebe9383cSRichard Henderson } 404ebe9383cSRichard Henderson 405ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 406ebe9383cSRichard Henderson { 407ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4080992a930SRichard Henderson if (rt == 0) { 4090992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4100992a930SRichard Henderson } else { 411ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 412ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 413ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 414ebe9383cSRichard Henderson } 4150992a930SRichard Henderson return ret; 416ebe9383cSRichard Henderson } 417ebe9383cSRichard Henderson 41896d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 41996d6407fSRichard Henderson { 420ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 42196d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 42296d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 42396d6407fSRichard Henderson } 42496d6407fSRichard Henderson 42596d6407fSRichard Henderson #undef HI_OFS 42696d6407fSRichard Henderson #undef LO_OFS 42796d6407fSRichard Henderson 42896d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 42996d6407fSRichard Henderson { 43096d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 431ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 43296d6407fSRichard Henderson return ret; 43396d6407fSRichard Henderson } 43496d6407fSRichard Henderson 435ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 436ebe9383cSRichard Henderson { 437ebe9383cSRichard Henderson if (rt == 0) { 4380992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4390992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4400992a930SRichard Henderson return ret; 441ebe9383cSRichard Henderson } else { 442ebe9383cSRichard Henderson return load_frd(rt); 443ebe9383cSRichard Henderson } 444ebe9383cSRichard Henderson } 445ebe9383cSRichard Henderson 44696d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 44796d6407fSRichard Henderson { 448ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 44996d6407fSRichard Henderson } 45096d6407fSRichard Henderson 45133423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 45233423472SRichard Henderson { 45333423472SRichard Henderson #ifdef CONFIG_USER_ONLY 45433423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 45533423472SRichard Henderson #else 45633423472SRichard Henderson if (reg < 4) { 45733423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 458494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 459494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 46033423472SRichard Henderson } else { 461ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 46233423472SRichard Henderson } 46333423472SRichard Henderson #endif 46433423472SRichard Henderson } 46533423472SRichard Henderson 466129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 467129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 468129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 469129e9cc3SRichard Henderson { 470129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 471129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 472129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 473129e9cc3SRichard Henderson 474129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 475129e9cc3SRichard Henderson 476129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 4776e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 478aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 4796fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 480129e9cc3SRichard Henderson } 481129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 482129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 483129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 484129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 485129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 4866fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 487129e9cc3SRichard Henderson } 488129e9cc3SRichard Henderson 4896fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 490129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 491129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 492129e9cc3SRichard Henderson } 493129e9cc3SRichard Henderson } 494129e9cc3SRichard Henderson 495129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 496129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 497129e9cc3SRichard Henderson { 498129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 499129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 5006fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 501129e9cc3SRichard Henderson } 502129e9cc3SRichard Henderson return; 503129e9cc3SRichard Henderson } 5046e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 5056fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 506129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 507129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 508129e9cc3SRichard Henderson } 509129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 510129e9cc3SRichard Henderson } 511129e9cc3SRichard Henderson 512129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 513129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 514129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 515129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 516129e9cc3SRichard Henderson { 517129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 5186fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 519129e9cc3SRichard Henderson } 520129e9cc3SRichard Henderson } 521129e9cc3SRichard Henderson 522129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 52340f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 52440f9f908SRichard Henderson it may be tail-called from a translate function. */ 52531234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 526129e9cc3SRichard Henderson { 527129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 52831234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 529129e9cc3SRichard Henderson 530f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 531f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 532f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 533f49b3537SRichard Henderson 534129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 535129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 536129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 537129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 53831234768SRichard Henderson return true; 539129e9cc3SRichard Henderson } 540129e9cc3SRichard Henderson ctx->null_lab = NULL; 541129e9cc3SRichard Henderson 542129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 543129e9cc3SRichard Henderson /* The next instruction will be unconditional, 544129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 545129e9cc3SRichard Henderson gen_set_label(null_lab); 546129e9cc3SRichard Henderson } else { 547129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 548129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 549129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 550129e9cc3SRichard Henderson label we have the proper value in place. */ 551129e9cc3SRichard Henderson nullify_save(ctx); 552129e9cc3SRichard Henderson gen_set_label(null_lab); 553129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 554129e9cc3SRichard Henderson } 555869051eaSRichard Henderson if (status == DISAS_NORETURN) { 55631234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 557129e9cc3SRichard Henderson } 55831234768SRichard Henderson return true; 559129e9cc3SRichard Henderson } 560129e9cc3SRichard Henderson 561c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx) 562698240d1SRichard Henderson { 563698240d1SRichard Henderson return (ctx->tb_flags & PSW_W 564698240d1SRichard Henderson ? MAKE_64BIT_MASK(0, 62) 565698240d1SRichard Henderson : MAKE_64BIT_MASK(0, 32)); 566698240d1SRichard Henderson } 567698240d1SRichard Henderson 5686fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 5696fd0c7bcSRichard Henderson uint64_t ival, TCGv_i64 vval) 57061766fe9SRichard Henderson { 571c53e401eSRichard Henderson uint64_t mask = gva_offset_mask(ctx); 572f13bf343SRichard Henderson 573f13bf343SRichard Henderson if (ival != -1) { 5746fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, ival & mask); 575f13bf343SRichard Henderson return; 576f13bf343SRichard Henderson } 577f13bf343SRichard Henderson tcg_debug_assert(vval != NULL); 578f13bf343SRichard Henderson 579f13bf343SRichard Henderson /* 580f13bf343SRichard Henderson * We know that the IAOQ is already properly masked. 581f13bf343SRichard Henderson * This optimization is primarily for "iaoq_f = iaoq_b". 582f13bf343SRichard Henderson */ 583f13bf343SRichard Henderson if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) { 5846fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, vval); 58561766fe9SRichard Henderson } else { 5866fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, vval, mask); 58761766fe9SRichard Henderson } 58861766fe9SRichard Henderson } 58961766fe9SRichard Henderson 590c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp) 59161766fe9SRichard Henderson { 59261766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 59361766fe9SRichard Henderson } 59461766fe9SRichard Henderson 59561766fe9SRichard Henderson static void gen_excp_1(int exception) 59661766fe9SRichard Henderson { 597ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 59861766fe9SRichard Henderson } 59961766fe9SRichard Henderson 60031234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 60161766fe9SRichard Henderson { 602741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 603741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 604129e9cc3SRichard Henderson nullify_save(ctx); 60561766fe9SRichard Henderson gen_excp_1(exception); 60631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 60761766fe9SRichard Henderson } 60861766fe9SRichard Henderson 60931234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 6101a19da0dSRichard Henderson { 61131234768SRichard Henderson nullify_over(ctx); 6126fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 613ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 61431234768SRichard Henderson gen_excp(ctx, exc); 61531234768SRichard Henderson return nullify_end(ctx); 6161a19da0dSRichard Henderson } 6171a19da0dSRichard Henderson 61831234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 61961766fe9SRichard Henderson { 62031234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 62161766fe9SRichard Henderson } 62261766fe9SRichard Henderson 62340f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 62440f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 62540f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 62640f9f908SRichard Henderson #else 627e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 628e1b5a5edSRichard Henderson do { \ 629e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 63031234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 631e1b5a5edSRichard Henderson } \ 632e1b5a5edSRichard Henderson } while (0) 63340f9f908SRichard Henderson #endif 634e1b5a5edSRichard Henderson 635c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest) 63661766fe9SRichard Henderson { 63757f91498SRichard Henderson return translator_use_goto_tb(&ctx->base, dest); 63861766fe9SRichard Henderson } 63961766fe9SRichard Henderson 640129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 641129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 642129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 643129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 644129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 645129e9cc3SRichard Henderson { 646129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 647129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 648129e9cc3SRichard Henderson } 649129e9cc3SRichard Henderson 65061766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 651c53e401eSRichard Henderson uint64_t f, uint64_t b) 65261766fe9SRichard Henderson { 65361766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 65461766fe9SRichard Henderson tcg_gen_goto_tb(which); 655a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL); 656a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL); 65707ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 65861766fe9SRichard Henderson } else { 659741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b); 660741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var); 6617f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 66261766fe9SRichard Henderson } 66361766fe9SRichard Henderson } 66461766fe9SRichard Henderson 665b47a4a02SSven Schnelle static bool cond_need_sv(int c) 666b47a4a02SSven Schnelle { 667b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 668b47a4a02SSven Schnelle } 669b47a4a02SSven Schnelle 670b47a4a02SSven Schnelle static bool cond_need_cb(int c) 671b47a4a02SSven Schnelle { 672b47a4a02SSven Schnelle return c == 4 || c == 5; 673b47a4a02SSven Schnelle } 674b47a4a02SSven Schnelle 6756fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */ 67672ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d) 67772ca8753SRichard Henderson { 678c53e401eSRichard Henderson return !(ctx->is_pa20 && d); 67972ca8753SRichard Henderson } 68072ca8753SRichard Henderson 681b47a4a02SSven Schnelle /* 682b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 683b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 684b47a4a02SSven Schnelle */ 685b2167459SRichard Henderson 686a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 6876fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv) 688b2167459SRichard Henderson { 689b2167459SRichard Henderson DisasCond cond; 6906fd0c7bcSRichard Henderson TCGv_i64 tmp; 691b2167459SRichard Henderson 692b2167459SRichard Henderson switch (cf >> 1) { 693b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 694b2167459SRichard Henderson cond = cond_make_f(); 695b2167459SRichard Henderson break; 696b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 697a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 698aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6996fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 700a751eb31SRichard Henderson res = tmp; 701a751eb31SRichard Henderson } 702b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 703b2167459SRichard Henderson break; 704b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 705aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7066fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 707a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7086fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, tmp); 709a751eb31SRichard Henderson } 710b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_LT, tmp); 711b2167459SRichard Henderson break; 712b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 713b47a4a02SSven Schnelle /* 714b47a4a02SSven Schnelle * Simplify: 715b47a4a02SSven Schnelle * (N ^ V) | Z 716b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 717b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 718b47a4a02SSven Schnelle * (~(res ^ sv) >= 0) | !res 719b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31) | !res 720b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31 & res) 721b47a4a02SSven Schnelle */ 722aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7236fd0c7bcSRichard Henderson tcg_gen_eqv_i64(tmp, res, sv); 724a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7256fd0c7bcSRichard Henderson tcg_gen_sextract_i64(tmp, tmp, 31, 1); 7266fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 7276fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 728a751eb31SRichard Henderson } else { 7296fd0c7bcSRichard Henderson tcg_gen_sari_i64(tmp, tmp, 63); 7306fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 731a751eb31SRichard Henderson } 732b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 733b2167459SRichard Henderson break; 734b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 735a751eb31SRichard Henderson /* Only bit 0 of cb_msb is ever set. */ 736b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 737b2167459SRichard Henderson break; 738b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 739aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7406fd0c7bcSRichard Henderson tcg_gen_neg_i64(tmp, cb_msb); 7416fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 742a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7436fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 744a751eb31SRichard Henderson } 745b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 746b2167459SRichard Henderson break; 747b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 748a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 749aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7506fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, sv); 751a751eb31SRichard Henderson sv = tmp; 752a751eb31SRichard Henderson } 753b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 754b2167459SRichard Henderson break; 755b2167459SRichard Henderson case 7: /* OD / EV */ 756aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7576fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, res, 1); 758b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_NE, tmp); 759b2167459SRichard Henderson break; 760b2167459SRichard Henderson default: 761b2167459SRichard Henderson g_assert_not_reached(); 762b2167459SRichard Henderson } 763b2167459SRichard Henderson if (cf & 1) { 764b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 765b2167459SRichard Henderson } 766b2167459SRichard Henderson 767b2167459SRichard Henderson return cond; 768b2167459SRichard Henderson } 769b2167459SRichard Henderson 770b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 771b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 772b2167459SRichard Henderson deleted as unused. */ 773b2167459SRichard Henderson 7744fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 7756fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 7766fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 777b2167459SRichard Henderson { 7784fe9533aSRichard Henderson TCGCond tc; 7794fe9533aSRichard Henderson bool ext_uns; 780b2167459SRichard Henderson 781b2167459SRichard Henderson switch (cf >> 1) { 782b2167459SRichard Henderson case 1: /* = / <> */ 7834fe9533aSRichard Henderson tc = TCG_COND_EQ; 7844fe9533aSRichard Henderson ext_uns = true; 785b2167459SRichard Henderson break; 786b2167459SRichard Henderson case 2: /* < / >= */ 7874fe9533aSRichard Henderson tc = TCG_COND_LT; 7884fe9533aSRichard Henderson ext_uns = false; 789b2167459SRichard Henderson break; 790b2167459SRichard Henderson case 3: /* <= / > */ 7914fe9533aSRichard Henderson tc = TCG_COND_LE; 7924fe9533aSRichard Henderson ext_uns = false; 793b2167459SRichard Henderson break; 794b2167459SRichard Henderson case 4: /* << / >>= */ 7954fe9533aSRichard Henderson tc = TCG_COND_LTU; 7964fe9533aSRichard Henderson ext_uns = true; 797b2167459SRichard Henderson break; 798b2167459SRichard Henderson case 5: /* <<= / >> */ 7994fe9533aSRichard Henderson tc = TCG_COND_LEU; 8004fe9533aSRichard Henderson ext_uns = true; 801b2167459SRichard Henderson break; 802b2167459SRichard Henderson default: 803a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 804b2167459SRichard Henderson } 805b2167459SRichard Henderson 8064fe9533aSRichard Henderson if (cf & 1) { 8074fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 8084fe9533aSRichard Henderson } 8094fe9533aSRichard Henderson if (cond_need_ext(ctx, d)) { 810aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 811aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 8124fe9533aSRichard Henderson 8134fe9533aSRichard Henderson if (ext_uns) { 8146fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 8156fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 8164fe9533aSRichard Henderson } else { 8176fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 8186fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 8194fe9533aSRichard Henderson } 8204fe9533aSRichard Henderson return cond_make_tmp(tc, t1, t2); 8214fe9533aSRichard Henderson } 8224fe9533aSRichard Henderson return cond_make(tc, in1, in2); 823b2167459SRichard Henderson } 824b2167459SRichard Henderson 825df0232feSRichard Henderson /* 826df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 827df0232feSRichard Henderson * computed, and use of them is undefined. 828df0232feSRichard Henderson * 829df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 830df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 831df0232feSRichard Henderson * how cases c={2,3} are treated. 832df0232feSRichard Henderson */ 833b2167459SRichard Henderson 834b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 8356fd0c7bcSRichard Henderson TCGv_i64 res) 836b2167459SRichard Henderson { 837b5af8423SRichard Henderson TCGCond tc; 838b5af8423SRichard Henderson bool ext_uns; 839a751eb31SRichard Henderson 840df0232feSRichard Henderson switch (cf) { 841df0232feSRichard Henderson case 0: /* never */ 842df0232feSRichard Henderson case 9: /* undef, C */ 843df0232feSRichard Henderson case 11: /* undef, C & !Z */ 844df0232feSRichard Henderson case 12: /* undef, V */ 845df0232feSRichard Henderson return cond_make_f(); 846df0232feSRichard Henderson 847df0232feSRichard Henderson case 1: /* true */ 848df0232feSRichard Henderson case 8: /* undef, !C */ 849df0232feSRichard Henderson case 10: /* undef, !C | Z */ 850df0232feSRichard Henderson case 13: /* undef, !V */ 851df0232feSRichard Henderson return cond_make_t(); 852df0232feSRichard Henderson 853df0232feSRichard Henderson case 2: /* == */ 854b5af8423SRichard Henderson tc = TCG_COND_EQ; 855b5af8423SRichard Henderson ext_uns = true; 856b5af8423SRichard Henderson break; 857df0232feSRichard Henderson case 3: /* <> */ 858b5af8423SRichard Henderson tc = TCG_COND_NE; 859b5af8423SRichard Henderson ext_uns = true; 860b5af8423SRichard Henderson break; 861df0232feSRichard Henderson case 4: /* < */ 862b5af8423SRichard Henderson tc = TCG_COND_LT; 863b5af8423SRichard Henderson ext_uns = false; 864b5af8423SRichard Henderson break; 865df0232feSRichard Henderson case 5: /* >= */ 866b5af8423SRichard Henderson tc = TCG_COND_GE; 867b5af8423SRichard Henderson ext_uns = false; 868b5af8423SRichard Henderson break; 869df0232feSRichard Henderson case 6: /* <= */ 870b5af8423SRichard Henderson tc = TCG_COND_LE; 871b5af8423SRichard Henderson ext_uns = false; 872b5af8423SRichard Henderson break; 873df0232feSRichard Henderson case 7: /* > */ 874b5af8423SRichard Henderson tc = TCG_COND_GT; 875b5af8423SRichard Henderson ext_uns = false; 876b5af8423SRichard Henderson break; 877df0232feSRichard Henderson 878df0232feSRichard Henderson case 14: /* OD */ 879df0232feSRichard Henderson case 15: /* EV */ 880a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, NULL); 881df0232feSRichard Henderson 882df0232feSRichard Henderson default: 883df0232feSRichard Henderson g_assert_not_reached(); 884b2167459SRichard Henderson } 885b5af8423SRichard Henderson 886b5af8423SRichard Henderson if (cond_need_ext(ctx, d)) { 887aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 888b5af8423SRichard Henderson 889b5af8423SRichard Henderson if (ext_uns) { 8906fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 891b5af8423SRichard Henderson } else { 8926fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 893b5af8423SRichard Henderson } 894b5af8423SRichard Henderson return cond_make_0_tmp(tc, tmp); 895b5af8423SRichard Henderson } 896b5af8423SRichard Henderson return cond_make_0(tc, res); 897b2167459SRichard Henderson } 898b2167459SRichard Henderson 89998cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 90098cd9ca7SRichard Henderson 9014fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 9026fd0c7bcSRichard Henderson TCGv_i64 res) 90398cd9ca7SRichard Henderson { 90498cd9ca7SRichard Henderson unsigned c, f; 90598cd9ca7SRichard Henderson 90698cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 90798cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 90898cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 90998cd9ca7SRichard Henderson c = orig & 3; 91098cd9ca7SRichard Henderson if (c == 3) { 91198cd9ca7SRichard Henderson c = 7; 91298cd9ca7SRichard Henderson } 91398cd9ca7SRichard Henderson f = (orig & 4) / 4; 91498cd9ca7SRichard Henderson 915b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 91698cd9ca7SRichard Henderson } 91798cd9ca7SRichard Henderson 918b2167459SRichard Henderson /* Similar, but for unit conditions. */ 919b2167459SRichard Henderson 9206fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res, 9216fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 922b2167459SRichard Henderson { 923b2167459SRichard Henderson DisasCond cond; 9246fd0c7bcSRichard Henderson TCGv_i64 tmp, cb = NULL; 925c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 926b2167459SRichard Henderson 927b2167459SRichard Henderson if (cf & 8) { 928b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 929b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 930b2167459SRichard Henderson * leaves us with carry bits spread across two words. 931b2167459SRichard Henderson */ 932aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 933aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9346fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, in1, in2); 9356fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, in1, in2); 9366fd0c7bcSRichard Henderson tcg_gen_andc_i64(cb, cb, res); 9376fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, cb, tmp); 938b2167459SRichard Henderson } 939b2167459SRichard Henderson 940b2167459SRichard Henderson switch (cf >> 1) { 941b2167459SRichard Henderson case 0: /* never / TR */ 942b2167459SRichard Henderson case 1: /* undefined */ 943b2167459SRichard Henderson case 5: /* undefined */ 944b2167459SRichard Henderson cond = cond_make_f(); 945b2167459SRichard Henderson break; 946b2167459SRichard Henderson 947b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 948b2167459SRichard Henderson /* See hasless(v,1) from 949b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 950b2167459SRichard Henderson */ 951aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9526fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u); 9536fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9546fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u); 955b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 956b2167459SRichard Henderson break; 957b2167459SRichard Henderson 958b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 959aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9606fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u); 9616fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9626fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u); 963b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 964b2167459SRichard Henderson break; 965b2167459SRichard Henderson 966b2167459SRichard Henderson case 4: /* SDC / NDC */ 9676fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u); 968b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 969b2167459SRichard Henderson break; 970b2167459SRichard Henderson 971b2167459SRichard Henderson case 6: /* SBC / NBC */ 9726fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u); 973b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 974b2167459SRichard Henderson break; 975b2167459SRichard Henderson 976b2167459SRichard Henderson case 7: /* SHC / NHC */ 9776fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u); 978b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 979b2167459SRichard Henderson break; 980b2167459SRichard Henderson 981b2167459SRichard Henderson default: 982b2167459SRichard Henderson g_assert_not_reached(); 983b2167459SRichard Henderson } 984b2167459SRichard Henderson if (cf & 1) { 985b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 986b2167459SRichard Henderson } 987b2167459SRichard Henderson 988b2167459SRichard Henderson return cond; 989b2167459SRichard Henderson } 990b2167459SRichard Henderson 9916fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 9926fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 99372ca8753SRichard Henderson { 99472ca8753SRichard Henderson if (cond_need_ext(ctx, d)) { 995aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 9966fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 99772ca8753SRichard Henderson return t; 99872ca8753SRichard Henderson } 99972ca8753SRichard Henderson return cb_msb; 100072ca8753SRichard Henderson } 100172ca8753SRichard Henderson 10026fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 100372ca8753SRichard Henderson { 100472ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 100572ca8753SRichard Henderson } 100672ca8753SRichard Henderson 1007b2167459SRichard Henderson /* Compute signed overflow for addition. */ 10086fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 10096fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1010b2167459SRichard Henderson { 1011aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1012aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1013b2167459SRichard Henderson 10146fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10156fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10166fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 1017b2167459SRichard Henderson 1018b2167459SRichard Henderson return sv; 1019b2167459SRichard Henderson } 1020b2167459SRichard Henderson 1021b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 10226fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 10236fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1024b2167459SRichard Henderson { 1025aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1026aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1027b2167459SRichard Henderson 10286fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10296fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10306fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 1031b2167459SRichard Henderson 1032b2167459SRichard Henderson return sv; 1033b2167459SRichard Henderson } 1034b2167459SRichard Henderson 10356fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 10366fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1037faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1038b2167459SRichard Henderson { 10396fd0c7bcSRichard Henderson TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp; 1040b2167459SRichard Henderson unsigned c = cf >> 1; 1041b2167459SRichard Henderson DisasCond cond; 1042b2167459SRichard Henderson 1043aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1044f764718dSRichard Henderson cb = NULL; 1045f764718dSRichard Henderson cb_msb = NULL; 1046bdcccc17SRichard Henderson cb_cond = NULL; 1047b2167459SRichard Henderson 1048b2167459SRichard Henderson if (shift) { 1049aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10506fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1051b2167459SRichard Henderson in1 = tmp; 1052b2167459SRichard Henderson } 1053b2167459SRichard Henderson 1054b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1055aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1056aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1057bdcccc17SRichard Henderson 1058a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1059b2167459SRichard Henderson if (is_c) { 10606fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1061a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1062b2167459SRichard Henderson } 10636fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 10646fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1065bdcccc17SRichard Henderson if (cond_need_cb(c)) { 1066bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 1067b2167459SRichard Henderson } 1068b2167459SRichard Henderson } else { 10696fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1070b2167459SRichard Henderson if (is_c) { 10716fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1072b2167459SRichard Henderson } 1073b2167459SRichard Henderson } 1074b2167459SRichard Henderson 1075b2167459SRichard Henderson /* Compute signed overflow if required. */ 1076f764718dSRichard Henderson sv = NULL; 1077b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1078b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 1079b2167459SRichard Henderson if (is_tsv) { 1080b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 1081ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1082b2167459SRichard Henderson } 1083b2167459SRichard Henderson } 1084b2167459SRichard Henderson 1085b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1086a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, cb_cond, sv); 1087b2167459SRichard Henderson if (is_tc) { 1088aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10896fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1090ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1091b2167459SRichard Henderson } 1092b2167459SRichard Henderson 1093b2167459SRichard Henderson /* Write back the result. */ 1094b2167459SRichard Henderson if (!is_l) { 1095b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1096b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1097b2167459SRichard Henderson } 1098b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1099b2167459SRichard Henderson 1100b2167459SRichard Henderson /* Install the new nullification. */ 1101b2167459SRichard Henderson cond_free(&ctx->null_cond); 1102b2167459SRichard Henderson ctx->null_cond = cond; 1103b2167459SRichard Henderson } 1104b2167459SRichard Henderson 1105faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 11060c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 11070c982a28SRichard Henderson { 11086fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 11090c982a28SRichard Henderson 11100c982a28SRichard Henderson if (a->cf) { 11110c982a28SRichard Henderson nullify_over(ctx); 11120c982a28SRichard Henderson } 11130c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 11140c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1115faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1116faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 11170c982a28SRichard Henderson return nullify_end(ctx); 11180c982a28SRichard Henderson } 11190c982a28SRichard Henderson 11200588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 11210588e061SRichard Henderson bool is_tsv, bool is_tc) 11220588e061SRichard Henderson { 11236fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11240588e061SRichard Henderson 11250588e061SRichard Henderson if (a->cf) { 11260588e061SRichard Henderson nullify_over(ctx); 11270588e061SRichard Henderson } 11286fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11290588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1130faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1131faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 11320588e061SRichard Henderson return nullify_end(ctx); 11330588e061SRichard Henderson } 11340588e061SRichard Henderson 11356fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 11366fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 113763c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1138b2167459SRichard Henderson { 1139a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1140b2167459SRichard Henderson unsigned c = cf >> 1; 1141b2167459SRichard Henderson DisasCond cond; 1142b2167459SRichard Henderson 1143aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1144aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1145aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1146b2167459SRichard Henderson 1147b2167459SRichard Henderson if (is_b) { 1148b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 11496fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1150a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1151a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1152a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 11536fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 11546fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1155b2167459SRichard Henderson } else { 1156bdcccc17SRichard Henderson /* 1157bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1158bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1159bdcccc17SRichard Henderson */ 11606fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1161a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 11626fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 11636fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1164b2167459SRichard Henderson } 1165b2167459SRichard Henderson 1166b2167459SRichard Henderson /* Compute signed overflow if required. */ 1167f764718dSRichard Henderson sv = NULL; 1168b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1169b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1170b2167459SRichard Henderson if (is_tsv) { 1171ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1172b2167459SRichard Henderson } 1173b2167459SRichard Henderson } 1174b2167459SRichard Henderson 1175b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1176b2167459SRichard Henderson if (!is_b) { 11774fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1178b2167459SRichard Henderson } else { 1179a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1180b2167459SRichard Henderson } 1181b2167459SRichard Henderson 1182b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1183b2167459SRichard Henderson if (is_tc) { 1184aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11856fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1186ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1187b2167459SRichard Henderson } 1188b2167459SRichard Henderson 1189b2167459SRichard Henderson /* Write back the result. */ 1190b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1191b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1192b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1193b2167459SRichard Henderson 1194b2167459SRichard Henderson /* Install the new nullification. */ 1195b2167459SRichard Henderson cond_free(&ctx->null_cond); 1196b2167459SRichard Henderson ctx->null_cond = cond; 1197b2167459SRichard Henderson } 1198b2167459SRichard Henderson 119963c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12000c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 12010c982a28SRichard Henderson { 12026fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12030c982a28SRichard Henderson 12040c982a28SRichard Henderson if (a->cf) { 12050c982a28SRichard Henderson nullify_over(ctx); 12060c982a28SRichard Henderson } 12070c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12080c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 120963c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 12100c982a28SRichard Henderson return nullify_end(ctx); 12110c982a28SRichard Henderson } 12120c982a28SRichard Henderson 12130588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 12140588e061SRichard Henderson { 12156fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 12160588e061SRichard Henderson 12170588e061SRichard Henderson if (a->cf) { 12180588e061SRichard Henderson nullify_over(ctx); 12190588e061SRichard Henderson } 12206fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 12210588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 122263c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 122363c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 12240588e061SRichard Henderson return nullify_end(ctx); 12250588e061SRichard Henderson } 12260588e061SRichard Henderson 12276fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12286fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1229b2167459SRichard Henderson { 12306fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1231b2167459SRichard Henderson DisasCond cond; 1232b2167459SRichard Henderson 1233aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 12346fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1235b2167459SRichard Henderson 1236b2167459SRichard Henderson /* Compute signed overflow if required. */ 1237f764718dSRichard Henderson sv = NULL; 1238b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1239b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1240b2167459SRichard Henderson } 1241b2167459SRichard Henderson 1242b2167459SRichard Henderson /* Form the condition for the compare. */ 12434fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1244b2167459SRichard Henderson 1245b2167459SRichard Henderson /* Clear. */ 12466fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1247b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1248b2167459SRichard Henderson 1249b2167459SRichard Henderson /* Install the new nullification. */ 1250b2167459SRichard Henderson cond_free(&ctx->null_cond); 1251b2167459SRichard Henderson ctx->null_cond = cond; 1252b2167459SRichard Henderson } 1253b2167459SRichard Henderson 12546fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12556fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 12566fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1257b2167459SRichard Henderson { 12586fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1259b2167459SRichard Henderson 1260b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1261b2167459SRichard Henderson fn(dest, in1, in2); 1262b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1263b2167459SRichard Henderson 1264b2167459SRichard Henderson /* Install the new nullification. */ 1265b2167459SRichard Henderson cond_free(&ctx->null_cond); 1266b2167459SRichard Henderson if (cf) { 1267b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1268b2167459SRichard Henderson } 1269b2167459SRichard Henderson } 1270b2167459SRichard Henderson 1271fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12726fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 12730c982a28SRichard Henderson { 12746fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12750c982a28SRichard Henderson 12760c982a28SRichard Henderson if (a->cf) { 12770c982a28SRichard Henderson nullify_over(ctx); 12780c982a28SRichard Henderson } 12790c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12800c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1281fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 12820c982a28SRichard Henderson return nullify_end(ctx); 12830c982a28SRichard Henderson } 12840c982a28SRichard Henderson 12856fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12866fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, bool is_tc, 12876fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1288b2167459SRichard Henderson { 12896fd0c7bcSRichard Henderson TCGv_i64 dest; 1290b2167459SRichard Henderson DisasCond cond; 1291b2167459SRichard Henderson 1292b2167459SRichard Henderson if (cf == 0) { 1293b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 1294b2167459SRichard Henderson fn(dest, in1, in2); 1295b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1296b2167459SRichard Henderson cond_free(&ctx->null_cond); 1297b2167459SRichard Henderson } else { 1298aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1299b2167459SRichard Henderson fn(dest, in1, in2); 1300b2167459SRichard Henderson 130159963d8fSRichard Henderson cond = do_unit_cond(cf, d, dest, in1, in2); 1302b2167459SRichard Henderson 1303b2167459SRichard Henderson if (is_tc) { 1304aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 13056fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1306ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1307b2167459SRichard Henderson } 1308b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1309b2167459SRichard Henderson 1310b2167459SRichard Henderson cond_free(&ctx->null_cond); 1311b2167459SRichard Henderson ctx->null_cond = cond; 1312b2167459SRichard Henderson } 1313b2167459SRichard Henderson } 1314b2167459SRichard Henderson 131586f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 13168d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 13178d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 13188d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 13198d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 13206fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 132186f8d05fSRichard Henderson { 132286f8d05fSRichard Henderson TCGv_ptr ptr; 13236fd0c7bcSRichard Henderson TCGv_i64 tmp; 132486f8d05fSRichard Henderson TCGv_i64 spc; 132586f8d05fSRichard Henderson 132686f8d05fSRichard Henderson if (sp != 0) { 13278d6ae7fbSRichard Henderson if (sp < 0) { 13288d6ae7fbSRichard Henderson sp = ~sp; 13298d6ae7fbSRichard Henderson } 13306fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 13318d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 13328d6ae7fbSRichard Henderson return spc; 133386f8d05fSRichard Henderson } 1334494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1335494737b7SRichard Henderson return cpu_srH; 1336494737b7SRichard Henderson } 133786f8d05fSRichard Henderson 133886f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1339aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 13406fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 134186f8d05fSRichard Henderson 1342698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 13436fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 13446fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 13456fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 134686f8d05fSRichard Henderson 1347ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 134886f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 134986f8d05fSRichard Henderson 135086f8d05fSRichard Henderson return spc; 135186f8d05fSRichard Henderson } 135286f8d05fSRichard Henderson #endif 135386f8d05fSRichard Henderson 13546fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1355c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 135686f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 135786f8d05fSRichard Henderson { 13586fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 13596fd0c7bcSRichard Henderson TCGv_i64 ofs; 13606fd0c7bcSRichard Henderson TCGv_i64 addr; 136186f8d05fSRichard Henderson 1362f5b5c857SRichard Henderson set_insn_breg(ctx, rb); 1363f5b5c857SRichard Henderson 136486f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 136586f8d05fSRichard Henderson if (rx) { 1366aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13676fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 13686fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 136986f8d05fSRichard Henderson } else if (disp || modify) { 1370aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13716fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 137286f8d05fSRichard Henderson } else { 137386f8d05fSRichard Henderson ofs = base; 137486f8d05fSRichard Henderson } 137586f8d05fSRichard Henderson 137686f8d05fSRichard Henderson *pofs = ofs; 13776fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 1378d265360fSRichard Henderson tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx)); 1379698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 138086f8d05fSRichard Henderson if (!is_phys) { 1381d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 138286f8d05fSRichard Henderson } 138386f8d05fSRichard Henderson #endif 138486f8d05fSRichard Henderson } 138586f8d05fSRichard Henderson 138696d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 138796d6407fSRichard Henderson * < 0 for pre-modify, 138896d6407fSRichard Henderson * > 0 for post-modify, 138996d6407fSRichard Henderson * = 0 for no base register update. 139096d6407fSRichard Henderson */ 139196d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1392c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 139314776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 139496d6407fSRichard Henderson { 13956fd0c7bcSRichard Henderson TCGv_i64 ofs; 13966fd0c7bcSRichard Henderson TCGv_i64 addr; 139796d6407fSRichard Henderson 139896d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 139996d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 140096d6407fSRichard Henderson 140186f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 140217fe594cSRichard Henderson MMU_DISABLED(ctx)); 1403c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 140486f8d05fSRichard Henderson if (modify) { 140586f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 140696d6407fSRichard Henderson } 140796d6407fSRichard Henderson } 140896d6407fSRichard Henderson 140996d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1410c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 141114776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 141296d6407fSRichard Henderson { 14136fd0c7bcSRichard Henderson TCGv_i64 ofs; 14146fd0c7bcSRichard Henderson TCGv_i64 addr; 141596d6407fSRichard Henderson 141696d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 141796d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 141896d6407fSRichard Henderson 141986f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 142017fe594cSRichard Henderson MMU_DISABLED(ctx)); 1421217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 142286f8d05fSRichard Henderson if (modify) { 142386f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 142496d6407fSRichard Henderson } 142596d6407fSRichard Henderson } 142696d6407fSRichard Henderson 142796d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1428c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 142914776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 143096d6407fSRichard Henderson { 14316fd0c7bcSRichard Henderson TCGv_i64 ofs; 14326fd0c7bcSRichard Henderson TCGv_i64 addr; 143396d6407fSRichard Henderson 143496d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 143596d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 143696d6407fSRichard Henderson 143786f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 143817fe594cSRichard Henderson MMU_DISABLED(ctx)); 1439217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 144086f8d05fSRichard Henderson if (modify) { 144186f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 144296d6407fSRichard Henderson } 144396d6407fSRichard Henderson } 144496d6407fSRichard Henderson 144596d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1446c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 144714776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 144896d6407fSRichard Henderson { 14496fd0c7bcSRichard Henderson TCGv_i64 ofs; 14506fd0c7bcSRichard Henderson TCGv_i64 addr; 145196d6407fSRichard Henderson 145296d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 145396d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 145496d6407fSRichard Henderson 145586f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 145617fe594cSRichard Henderson MMU_DISABLED(ctx)); 1457217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 145886f8d05fSRichard Henderson if (modify) { 145986f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 146096d6407fSRichard Henderson } 146196d6407fSRichard Henderson } 146296d6407fSRichard Henderson 14631cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1464c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 146514776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 146696d6407fSRichard Henderson { 14676fd0c7bcSRichard Henderson TCGv_i64 dest; 146896d6407fSRichard Henderson 146996d6407fSRichard Henderson nullify_over(ctx); 147096d6407fSRichard Henderson 147196d6407fSRichard Henderson if (modify == 0) { 147296d6407fSRichard Henderson /* No base register update. */ 147396d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 147496d6407fSRichard Henderson } else { 147596d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1476aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 147796d6407fSRichard Henderson } 14786fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 147996d6407fSRichard Henderson save_gpr(ctx, rt, dest); 148096d6407fSRichard Henderson 14811cd012a5SRichard Henderson return nullify_end(ctx); 148296d6407fSRichard Henderson } 148396d6407fSRichard Henderson 1484740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1485c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 148686f8d05fSRichard Henderson unsigned sp, int modify) 148796d6407fSRichard Henderson { 148896d6407fSRichard Henderson TCGv_i32 tmp; 148996d6407fSRichard Henderson 149096d6407fSRichard Henderson nullify_over(ctx); 149196d6407fSRichard Henderson 149296d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 149386f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 149496d6407fSRichard Henderson save_frw_i32(rt, tmp); 149596d6407fSRichard Henderson 149696d6407fSRichard Henderson if (rt == 0) { 1497ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 149896d6407fSRichard Henderson } 149996d6407fSRichard Henderson 1500740038d7SRichard Henderson return nullify_end(ctx); 150196d6407fSRichard Henderson } 150296d6407fSRichard Henderson 1503740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1504740038d7SRichard Henderson { 1505740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1506740038d7SRichard Henderson a->disp, a->sp, a->m); 1507740038d7SRichard Henderson } 1508740038d7SRichard Henderson 1509740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1510c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 151186f8d05fSRichard Henderson unsigned sp, int modify) 151296d6407fSRichard Henderson { 151396d6407fSRichard Henderson TCGv_i64 tmp; 151496d6407fSRichard Henderson 151596d6407fSRichard Henderson nullify_over(ctx); 151696d6407fSRichard Henderson 151796d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1518fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 151996d6407fSRichard Henderson save_frd(rt, tmp); 152096d6407fSRichard Henderson 152196d6407fSRichard Henderson if (rt == 0) { 1522ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 152396d6407fSRichard Henderson } 152496d6407fSRichard Henderson 1525740038d7SRichard Henderson return nullify_end(ctx); 1526740038d7SRichard Henderson } 1527740038d7SRichard Henderson 1528740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1529740038d7SRichard Henderson { 1530740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1531740038d7SRichard Henderson a->disp, a->sp, a->m); 153296d6407fSRichard Henderson } 153396d6407fSRichard Henderson 15341cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1535c53e401eSRichard Henderson int64_t disp, unsigned sp, 153614776ab5STony Nguyen int modify, MemOp mop) 153796d6407fSRichard Henderson { 153896d6407fSRichard Henderson nullify_over(ctx); 15396fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 15401cd012a5SRichard Henderson return nullify_end(ctx); 154196d6407fSRichard Henderson } 154296d6407fSRichard Henderson 1543740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1544c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 154586f8d05fSRichard Henderson unsigned sp, int modify) 154696d6407fSRichard Henderson { 154796d6407fSRichard Henderson TCGv_i32 tmp; 154896d6407fSRichard Henderson 154996d6407fSRichard Henderson nullify_over(ctx); 155096d6407fSRichard Henderson 155196d6407fSRichard Henderson tmp = load_frw_i32(rt); 155286f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 155396d6407fSRichard Henderson 1554740038d7SRichard Henderson return nullify_end(ctx); 155596d6407fSRichard Henderson } 155696d6407fSRichard Henderson 1557740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1558740038d7SRichard Henderson { 1559740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1560740038d7SRichard Henderson a->disp, a->sp, a->m); 1561740038d7SRichard Henderson } 1562740038d7SRichard Henderson 1563740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1564c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 156586f8d05fSRichard Henderson unsigned sp, int modify) 156696d6407fSRichard Henderson { 156796d6407fSRichard Henderson TCGv_i64 tmp; 156896d6407fSRichard Henderson 156996d6407fSRichard Henderson nullify_over(ctx); 157096d6407fSRichard Henderson 157196d6407fSRichard Henderson tmp = load_frd(rt); 1572fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 157396d6407fSRichard Henderson 1574740038d7SRichard Henderson return nullify_end(ctx); 1575740038d7SRichard Henderson } 1576740038d7SRichard Henderson 1577740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1578740038d7SRichard Henderson { 1579740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1580740038d7SRichard Henderson a->disp, a->sp, a->m); 158196d6407fSRichard Henderson } 158296d6407fSRichard Henderson 15831ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1584ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1585ebe9383cSRichard Henderson { 1586ebe9383cSRichard Henderson TCGv_i32 tmp; 1587ebe9383cSRichard Henderson 1588ebe9383cSRichard Henderson nullify_over(ctx); 1589ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1590ebe9383cSRichard Henderson 1591ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1592ebe9383cSRichard Henderson 1593ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 15941ca74648SRichard Henderson return nullify_end(ctx); 1595ebe9383cSRichard Henderson } 1596ebe9383cSRichard Henderson 15971ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1598ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1599ebe9383cSRichard Henderson { 1600ebe9383cSRichard Henderson TCGv_i32 dst; 1601ebe9383cSRichard Henderson TCGv_i64 src; 1602ebe9383cSRichard Henderson 1603ebe9383cSRichard Henderson nullify_over(ctx); 1604ebe9383cSRichard Henderson src = load_frd(ra); 1605ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1606ebe9383cSRichard Henderson 1607ad75a51eSRichard Henderson func(dst, tcg_env, src); 1608ebe9383cSRichard Henderson 1609ebe9383cSRichard Henderson save_frw_i32(rt, dst); 16101ca74648SRichard Henderson return nullify_end(ctx); 1611ebe9383cSRichard Henderson } 1612ebe9383cSRichard Henderson 16131ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1614ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1615ebe9383cSRichard Henderson { 1616ebe9383cSRichard Henderson TCGv_i64 tmp; 1617ebe9383cSRichard Henderson 1618ebe9383cSRichard Henderson nullify_over(ctx); 1619ebe9383cSRichard Henderson tmp = load_frd0(ra); 1620ebe9383cSRichard Henderson 1621ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1622ebe9383cSRichard Henderson 1623ebe9383cSRichard Henderson save_frd(rt, tmp); 16241ca74648SRichard Henderson return nullify_end(ctx); 1625ebe9383cSRichard Henderson } 1626ebe9383cSRichard Henderson 16271ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1628ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1629ebe9383cSRichard Henderson { 1630ebe9383cSRichard Henderson TCGv_i32 src; 1631ebe9383cSRichard Henderson TCGv_i64 dst; 1632ebe9383cSRichard Henderson 1633ebe9383cSRichard Henderson nullify_over(ctx); 1634ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1635ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1636ebe9383cSRichard Henderson 1637ad75a51eSRichard Henderson func(dst, tcg_env, src); 1638ebe9383cSRichard Henderson 1639ebe9383cSRichard Henderson save_frd(rt, dst); 16401ca74648SRichard Henderson return nullify_end(ctx); 1641ebe9383cSRichard Henderson } 1642ebe9383cSRichard Henderson 16431ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1644ebe9383cSRichard Henderson unsigned ra, unsigned rb, 164531234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1646ebe9383cSRichard Henderson { 1647ebe9383cSRichard Henderson TCGv_i32 a, b; 1648ebe9383cSRichard Henderson 1649ebe9383cSRichard Henderson nullify_over(ctx); 1650ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1651ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1652ebe9383cSRichard Henderson 1653ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1654ebe9383cSRichard Henderson 1655ebe9383cSRichard Henderson save_frw_i32(rt, a); 16561ca74648SRichard Henderson return nullify_end(ctx); 1657ebe9383cSRichard Henderson } 1658ebe9383cSRichard Henderson 16591ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1660ebe9383cSRichard Henderson unsigned ra, unsigned rb, 166131234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1662ebe9383cSRichard Henderson { 1663ebe9383cSRichard Henderson TCGv_i64 a, b; 1664ebe9383cSRichard Henderson 1665ebe9383cSRichard Henderson nullify_over(ctx); 1666ebe9383cSRichard Henderson a = load_frd0(ra); 1667ebe9383cSRichard Henderson b = load_frd0(rb); 1668ebe9383cSRichard Henderson 1669ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1670ebe9383cSRichard Henderson 1671ebe9383cSRichard Henderson save_frd(rt, a); 16721ca74648SRichard Henderson return nullify_end(ctx); 1673ebe9383cSRichard Henderson } 1674ebe9383cSRichard Henderson 167598cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 167698cd9ca7SRichard Henderson have already had nullification handled. */ 1677c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest, 167898cd9ca7SRichard Henderson unsigned link, bool is_n) 167998cd9ca7SRichard Henderson { 168098cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 168198cd9ca7SRichard Henderson if (link != 0) { 1682741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 168398cd9ca7SRichard Henderson } 168498cd9ca7SRichard Henderson ctx->iaoq_n = dest; 168598cd9ca7SRichard Henderson if (is_n) { 168698cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 168798cd9ca7SRichard Henderson } 168898cd9ca7SRichard Henderson } else { 168998cd9ca7SRichard Henderson nullify_over(ctx); 169098cd9ca7SRichard Henderson 169198cd9ca7SRichard Henderson if (link != 0) { 1692741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 169398cd9ca7SRichard Henderson } 169498cd9ca7SRichard Henderson 169598cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 169698cd9ca7SRichard Henderson nullify_set(ctx, 0); 169798cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 169898cd9ca7SRichard Henderson } else { 169998cd9ca7SRichard Henderson nullify_set(ctx, is_n); 170098cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 170198cd9ca7SRichard Henderson } 170298cd9ca7SRichard Henderson 170331234768SRichard Henderson nullify_end(ctx); 170498cd9ca7SRichard Henderson 170598cd9ca7SRichard Henderson nullify_set(ctx, 0); 170698cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 170731234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 170898cd9ca7SRichard Henderson } 170901afb7beSRichard Henderson return true; 171098cd9ca7SRichard Henderson } 171198cd9ca7SRichard Henderson 171298cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 171398cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1714c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 171598cd9ca7SRichard Henderson DisasCond *cond) 171698cd9ca7SRichard Henderson { 1717c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, disp); 171898cd9ca7SRichard Henderson TCGLabel *taken = NULL; 171998cd9ca7SRichard Henderson TCGCond c = cond->c; 172098cd9ca7SRichard Henderson bool n; 172198cd9ca7SRichard Henderson 172298cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 172398cd9ca7SRichard Henderson 172498cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 172598cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 172601afb7beSRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 172798cd9ca7SRichard Henderson } 172898cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 172901afb7beSRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 173098cd9ca7SRichard Henderson } 173198cd9ca7SRichard Henderson 173298cd9ca7SRichard Henderson taken = gen_new_label(); 17336fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 173498cd9ca7SRichard Henderson cond_free(cond); 173598cd9ca7SRichard Henderson 173698cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 173798cd9ca7SRichard Henderson n = is_n && disp < 0; 173898cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 173998cd9ca7SRichard Henderson nullify_set(ctx, 0); 1740a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 174198cd9ca7SRichard Henderson } else { 174298cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 174398cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 174498cd9ca7SRichard Henderson ctx->null_lab = NULL; 174598cd9ca7SRichard Henderson } 174698cd9ca7SRichard Henderson nullify_set(ctx, n); 1747c301f34eSRichard Henderson if (ctx->iaoq_n == -1) { 1748c301f34eSRichard Henderson /* The temporary iaoq_n_var died at the branch above. 1749c301f34eSRichard Henderson Regenerate it here instead of saving it. */ 17506fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 1751c301f34eSRichard Henderson } 1752a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 175398cd9ca7SRichard Henderson } 175498cd9ca7SRichard Henderson 175598cd9ca7SRichard Henderson gen_set_label(taken); 175698cd9ca7SRichard Henderson 175798cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 175898cd9ca7SRichard Henderson n = is_n && disp >= 0; 175998cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 176098cd9ca7SRichard Henderson nullify_set(ctx, 0); 1761a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, dest, dest + 4); 176298cd9ca7SRichard Henderson } else { 176398cd9ca7SRichard Henderson nullify_set(ctx, n); 1764a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 176598cd9ca7SRichard Henderson } 176698cd9ca7SRichard Henderson 176798cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 176898cd9ca7SRichard Henderson if (ctx->null_lab) { 176998cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 177098cd9ca7SRichard Henderson ctx->null_lab = NULL; 177131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 177298cd9ca7SRichard Henderson } else { 177331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 177498cd9ca7SRichard Henderson } 177501afb7beSRichard Henderson return true; 177698cd9ca7SRichard Henderson } 177798cd9ca7SRichard Henderson 177898cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 177998cd9ca7SRichard Henderson nullification of the branch itself. */ 17806fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest, 178198cd9ca7SRichard Henderson unsigned link, bool is_n) 178298cd9ca7SRichard Henderson { 17836fd0c7bcSRichard Henderson TCGv_i64 a0, a1, next, tmp; 178498cd9ca7SRichard Henderson TCGCond c; 178598cd9ca7SRichard Henderson 178698cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 178798cd9ca7SRichard Henderson 178898cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 178998cd9ca7SRichard Henderson if (link != 0) { 1790741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 179198cd9ca7SRichard Henderson } 1792aac0f603SRichard Henderson next = tcg_temp_new_i64(); 17936fd0c7bcSRichard Henderson tcg_gen_mov_i64(next, dest); 179498cd9ca7SRichard Henderson if (is_n) { 1795c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1796a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next); 17976fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, next, 4); 1798a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 1799c301f34eSRichard Henderson nullify_set(ctx, 0); 180031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 180101afb7beSRichard Henderson return true; 1802c301f34eSRichard Henderson } 180398cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 180498cd9ca7SRichard Henderson } 1805c301f34eSRichard Henderson ctx->iaoq_n = -1; 1806c301f34eSRichard Henderson ctx->iaoq_n_var = next; 180798cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 180898cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 180998cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 18104137cb83SRichard Henderson tracepoint in effect). Since the goto_ptr that we must use 181198cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 181298cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 181398cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 181498cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 181598cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 181698cd9ca7SRichard Henderson 181798cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 181898cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 181998cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 1820a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest); 1821aac0f603SRichard Henderson next = tcg_temp_new_i64(); 18226fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, dest, 4); 1823a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 182498cd9ca7SRichard Henderson 182598cd9ca7SRichard Henderson nullify_over(ctx); 182698cd9ca7SRichard Henderson if (link != 0) { 18279a91dd84SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 182898cd9ca7SRichard Henderson } 18297f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 183001afb7beSRichard Henderson return nullify_end(ctx); 183198cd9ca7SRichard Henderson } else { 183298cd9ca7SRichard Henderson c = ctx->null_cond.c; 183398cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 183498cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 183598cd9ca7SRichard Henderson 1836aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 1837aac0f603SRichard Henderson next = tcg_temp_new_i64(); 183898cd9ca7SRichard Henderson 1839741322f4SRichard Henderson copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var); 18406fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest); 184198cd9ca7SRichard Henderson ctx->iaoq_n = -1; 184298cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 184398cd9ca7SRichard Henderson 184498cd9ca7SRichard Henderson if (link != 0) { 18456fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 184698cd9ca7SRichard Henderson } 184798cd9ca7SRichard Henderson 184898cd9ca7SRichard Henderson if (is_n) { 184998cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 185098cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 185198cd9ca7SRichard Henderson to the branch. */ 18526fd0c7bcSRichard Henderson tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1); 185398cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 185498cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 185598cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 185698cd9ca7SRichard Henderson } else { 185798cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 185898cd9ca7SRichard Henderson } 185998cd9ca7SRichard Henderson } 186001afb7beSRichard Henderson return true; 186198cd9ca7SRichard Henderson } 186298cd9ca7SRichard Henderson 1863660eefe1SRichard Henderson /* Implement 1864660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1865660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1866660eefe1SRichard Henderson * else 1867660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1868660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1869660eefe1SRichard Henderson */ 18706fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1871660eefe1SRichard Henderson { 18726fd0c7bcSRichard Henderson TCGv_i64 dest; 1873660eefe1SRichard Henderson switch (ctx->privilege) { 1874660eefe1SRichard Henderson case 0: 1875660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 1876660eefe1SRichard Henderson return offset; 1877660eefe1SRichard Henderson case 3: 1878993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 1879aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18806fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1881660eefe1SRichard Henderson break; 1882660eefe1SRichard Henderson default: 1883aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18846fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 18856fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 18866fd0c7bcSRichard Henderson tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset); 1887660eefe1SRichard Henderson break; 1888660eefe1SRichard Henderson } 1889660eefe1SRichard Henderson return dest; 1890660eefe1SRichard Henderson } 1891660eefe1SRichard Henderson 1892ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 18937ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 18947ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 18957ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 18967ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 18977ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 18987ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 18997ad439dfSRichard Henderson aforementioned BE. */ 190031234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 19017ad439dfSRichard Henderson { 19026fd0c7bcSRichard Henderson TCGv_i64 tmp; 1903a0180973SRichard Henderson 19047ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 19057ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 19068b81968cSMichael Tokarev next insn within the privileged page. */ 19077ad439dfSRichard Henderson switch (ctx->null_cond.c) { 19087ad439dfSRichard Henderson case TCG_COND_NEVER: 19097ad439dfSRichard Henderson break; 19107ad439dfSRichard Henderson case TCG_COND_ALWAYS: 19116fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 19127ad439dfSRichard Henderson goto do_sigill; 19137ad439dfSRichard Henderson default: 19147ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 19157ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 19167ad439dfSRichard Henderson g_assert_not_reached(); 19177ad439dfSRichard Henderson } 19187ad439dfSRichard Henderson 19197ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 19207ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 19217ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 19227ad439dfSRichard Henderson under such conditions. */ 19237ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 19247ad439dfSRichard Henderson goto do_sigill; 19257ad439dfSRichard Henderson } 19267ad439dfSRichard Henderson 1927ebd0e151SRichard Henderson switch (ctx->iaoq_f & -4) { 19287ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 19292986721dSRichard Henderson gen_excp_1(EXCP_IMP); 193031234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 193131234768SRichard Henderson break; 19327ad439dfSRichard Henderson 19337ad439dfSRichard Henderson case 0xb0: /* LWS */ 19347ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 193531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 193631234768SRichard Henderson break; 19377ad439dfSRichard Henderson 19387ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 19396fd0c7bcSRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27])); 1940aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 19416fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_gr[31], 3); 1942a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 19436fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 1944a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 194531234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 194631234768SRichard Henderson break; 19477ad439dfSRichard Henderson 19487ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 19497ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 195031234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 195131234768SRichard Henderson break; 19527ad439dfSRichard Henderson 19537ad439dfSRichard Henderson default: 19547ad439dfSRichard Henderson do_sigill: 19552986721dSRichard Henderson gen_excp_1(EXCP_ILL); 195631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 195731234768SRichard Henderson break; 19587ad439dfSRichard Henderson } 19597ad439dfSRichard Henderson } 1960ba1d0b44SRichard Henderson #endif 19617ad439dfSRichard Henderson 1962deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 1963b2167459SRichard Henderson { 1964b2167459SRichard Henderson cond_free(&ctx->null_cond); 196531234768SRichard Henderson return true; 1966b2167459SRichard Henderson } 1967b2167459SRichard Henderson 196840f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 196998a9cb79SRichard Henderson { 197031234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 197198a9cb79SRichard Henderson } 197298a9cb79SRichard Henderson 1973e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 197498a9cb79SRichard Henderson { 197598a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 197698a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 197798a9cb79SRichard Henderson 197898a9cb79SRichard Henderson cond_free(&ctx->null_cond); 197931234768SRichard Henderson return true; 198098a9cb79SRichard Henderson } 198198a9cb79SRichard Henderson 1982c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 198398a9cb79SRichard Henderson { 1984c603e14aSRichard Henderson unsigned rt = a->t; 19856fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, rt); 19866fd0c7bcSRichard Henderson tcg_gen_movi_i64(tmp, ctx->iaoq_f); 198798a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 198898a9cb79SRichard Henderson 198998a9cb79SRichard Henderson cond_free(&ctx->null_cond); 199031234768SRichard Henderson return true; 199198a9cb79SRichard Henderson } 199298a9cb79SRichard Henderson 1993c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 199498a9cb79SRichard Henderson { 1995c603e14aSRichard Henderson unsigned rt = a->t; 1996c603e14aSRichard Henderson unsigned rs = a->sp; 199733423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 199898a9cb79SRichard Henderson 199933423472SRichard Henderson load_spr(ctx, t0, rs); 200033423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 200133423472SRichard Henderson 2002967662cdSRichard Henderson save_gpr(ctx, rt, t0); 200398a9cb79SRichard Henderson 200498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 200531234768SRichard Henderson return true; 200698a9cb79SRichard Henderson } 200798a9cb79SRichard Henderson 2008c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 200998a9cb79SRichard Henderson { 2010c603e14aSRichard Henderson unsigned rt = a->t; 2011c603e14aSRichard Henderson unsigned ctl = a->r; 20126fd0c7bcSRichard Henderson TCGv_i64 tmp; 201398a9cb79SRichard Henderson 201498a9cb79SRichard Henderson switch (ctl) { 201535136a77SRichard Henderson case CR_SAR: 2016c603e14aSRichard Henderson if (a->e == 0) { 201798a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 201898a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 20196fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 202098a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 202135136a77SRichard Henderson goto done; 202298a9cb79SRichard Henderson } 202398a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 202435136a77SRichard Henderson goto done; 202535136a77SRichard Henderson case CR_IT: /* Interval Timer */ 202635136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 202735136a77SRichard Henderson nullify_over(ctx); 202898a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2029dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 203049c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 203131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 203249c29d6cSRichard Henderson } else { 203349c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 203449c29d6cSRichard Henderson } 203598a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 203631234768SRichard Henderson return nullify_end(ctx); 203798a9cb79SRichard Henderson case 26: 203898a9cb79SRichard Henderson case 27: 203998a9cb79SRichard Henderson break; 204098a9cb79SRichard Henderson default: 204198a9cb79SRichard Henderson /* All other control registers are privileged. */ 204235136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 204335136a77SRichard Henderson break; 204498a9cb79SRichard Henderson } 204598a9cb79SRichard Henderson 2046aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20476fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 204835136a77SRichard Henderson save_gpr(ctx, rt, tmp); 204935136a77SRichard Henderson 205035136a77SRichard Henderson done: 205198a9cb79SRichard Henderson cond_free(&ctx->null_cond); 205231234768SRichard Henderson return true; 205398a9cb79SRichard Henderson } 205498a9cb79SRichard Henderson 2055c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 205633423472SRichard Henderson { 2057c603e14aSRichard Henderson unsigned rr = a->r; 2058c603e14aSRichard Henderson unsigned rs = a->sp; 2059967662cdSRichard Henderson TCGv_i64 tmp; 206033423472SRichard Henderson 206133423472SRichard Henderson if (rs >= 5) { 206233423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 206333423472SRichard Henderson } 206433423472SRichard Henderson nullify_over(ctx); 206533423472SRichard Henderson 2066967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2067967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 206833423472SRichard Henderson 206933423472SRichard Henderson if (rs >= 4) { 2070967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2071494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 207233423472SRichard Henderson } else { 2073967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 207433423472SRichard Henderson } 207533423472SRichard Henderson 207631234768SRichard Henderson return nullify_end(ctx); 207733423472SRichard Henderson } 207833423472SRichard Henderson 2079c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 208098a9cb79SRichard Henderson { 2081c603e14aSRichard Henderson unsigned ctl = a->t; 20826fd0c7bcSRichard Henderson TCGv_i64 reg; 20836fd0c7bcSRichard Henderson TCGv_i64 tmp; 208498a9cb79SRichard Henderson 208535136a77SRichard Henderson if (ctl == CR_SAR) { 20864845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2087aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20886fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 208998a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 209098a9cb79SRichard Henderson 209198a9cb79SRichard Henderson cond_free(&ctx->null_cond); 209231234768SRichard Henderson return true; 209398a9cb79SRichard Henderson } 209498a9cb79SRichard Henderson 209535136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 209635136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 209735136a77SRichard Henderson 2098c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 209935136a77SRichard Henderson nullify_over(ctx); 21004c34bab0SHelge Deller 21014c34bab0SHelge Deller if (ctx->is_pa20) { 21024845f015SSven Schnelle reg = load_gpr(ctx, a->r); 21034c34bab0SHelge Deller } else { 21044c34bab0SHelge Deller reg = tcg_temp_new_i64(); 21054c34bab0SHelge Deller tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 21064c34bab0SHelge Deller } 21074845f015SSven Schnelle 210835136a77SRichard Henderson switch (ctl) { 210935136a77SRichard Henderson case CR_IT: 2110ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 211135136a77SRichard Henderson break; 21124f5f2548SRichard Henderson case CR_EIRR: 2113ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 21144f5f2548SRichard Henderson break; 21154f5f2548SRichard Henderson case CR_EIEM: 2116ad75a51eSRichard Henderson gen_helper_write_eiem(tcg_env, reg); 211731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 21184f5f2548SRichard Henderson break; 21194f5f2548SRichard Henderson 212035136a77SRichard Henderson case CR_IIASQ: 212135136a77SRichard Henderson case CR_IIAOQ: 212235136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 212335136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2124aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21256fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 212635136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 21276fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 21286fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 212935136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 213035136a77SRichard Henderson break; 213135136a77SRichard Henderson 2132d5de20bdSSven Schnelle case CR_PID1: 2133d5de20bdSSven Schnelle case CR_PID2: 2134d5de20bdSSven Schnelle case CR_PID3: 2135d5de20bdSSven Schnelle case CR_PID4: 21366fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2137d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2138ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2139d5de20bdSSven Schnelle #endif 2140d5de20bdSSven Schnelle break; 2141d5de20bdSSven Schnelle 214235136a77SRichard Henderson default: 21436fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 214435136a77SRichard Henderson break; 214535136a77SRichard Henderson } 214631234768SRichard Henderson return nullify_end(ctx); 21474f5f2548SRichard Henderson #endif 214835136a77SRichard Henderson } 214935136a77SRichard Henderson 2150c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 215198a9cb79SRichard Henderson { 2152aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 215398a9cb79SRichard Henderson 21546fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 21556fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 215698a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 215798a9cb79SRichard Henderson 215898a9cb79SRichard Henderson cond_free(&ctx->null_cond); 215931234768SRichard Henderson return true; 216098a9cb79SRichard Henderson } 216198a9cb79SRichard Henderson 2162e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 216398a9cb79SRichard Henderson { 21646fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 216598a9cb79SRichard Henderson 21662330504cSHelge Deller #ifdef CONFIG_USER_ONLY 21672330504cSHelge Deller /* We don't implement space registers in user mode. */ 21686fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 21692330504cSHelge Deller #else 2170967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2171967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 21722330504cSHelge Deller #endif 2173e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 217498a9cb79SRichard Henderson 217598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 217631234768SRichard Henderson return true; 217798a9cb79SRichard Henderson } 217898a9cb79SRichard Henderson 2179e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2180e36f27efSRichard Henderson { 21817b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY 2182e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 21837b2d70a1SHelge Deller #else 21846fd0c7bcSRichard Henderson TCGv_i64 tmp; 2185e1b5a5edSRichard Henderson 21867b2d70a1SHelge Deller /* HP-UX 11i and HP ODE use rsm for read-access to PSW */ 21877b2d70a1SHelge Deller if (a->i) { 21887b2d70a1SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 21897b2d70a1SHelge Deller } 21907b2d70a1SHelge Deller 2191e1b5a5edSRichard Henderson nullify_over(ctx); 2192e1b5a5edSRichard Henderson 2193aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21946fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21956fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2196ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2197e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2198e1b5a5edSRichard Henderson 2199e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 220031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 220131234768SRichard Henderson return nullify_end(ctx); 2202e36f27efSRichard Henderson #endif 2203e1b5a5edSRichard Henderson } 2204e1b5a5edSRichard Henderson 2205e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2206e1b5a5edSRichard Henderson { 2207e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2208e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 22096fd0c7bcSRichard Henderson TCGv_i64 tmp; 2210e1b5a5edSRichard Henderson 2211e1b5a5edSRichard Henderson nullify_over(ctx); 2212e1b5a5edSRichard Henderson 2213aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22146fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 22156fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2216ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2217e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2218e1b5a5edSRichard Henderson 2219e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 222031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 222131234768SRichard Henderson return nullify_end(ctx); 2222e36f27efSRichard Henderson #endif 2223e1b5a5edSRichard Henderson } 2224e1b5a5edSRichard Henderson 2225c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2226e1b5a5edSRichard Henderson { 2227e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2228c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 22296fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2230e1b5a5edSRichard Henderson nullify_over(ctx); 2231e1b5a5edSRichard Henderson 2232c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2233aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2234ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2235e1b5a5edSRichard Henderson 2236e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 223731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 223831234768SRichard Henderson return nullify_end(ctx); 2239c603e14aSRichard Henderson #endif 2240e1b5a5edSRichard Henderson } 2241f49b3537SRichard Henderson 2242e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2243f49b3537SRichard Henderson { 2244f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2245e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2246f49b3537SRichard Henderson nullify_over(ctx); 2247f49b3537SRichard Henderson 2248e36f27efSRichard Henderson if (rfi_r) { 2249ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2250f49b3537SRichard Henderson } else { 2251ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2252f49b3537SRichard Henderson } 225331234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 225407ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 225531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2256f49b3537SRichard Henderson 225731234768SRichard Henderson return nullify_end(ctx); 2258e36f27efSRichard Henderson #endif 2259f49b3537SRichard Henderson } 22606210db05SHelge Deller 2261e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2262e36f27efSRichard Henderson { 2263e36f27efSRichard Henderson return do_rfi(ctx, false); 2264e36f27efSRichard Henderson } 2265e36f27efSRichard Henderson 2266e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2267e36f27efSRichard Henderson { 2268e36f27efSRichard Henderson return do_rfi(ctx, true); 2269e36f27efSRichard Henderson } 2270e36f27efSRichard Henderson 227196927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 22726210db05SHelge Deller { 22736210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 227496927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 22756210db05SHelge Deller nullify_over(ctx); 2276ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 227731234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 227831234768SRichard Henderson return nullify_end(ctx); 227996927adbSRichard Henderson #endif 22806210db05SHelge Deller } 228196927adbSRichard Henderson 228296927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 228396927adbSRichard Henderson { 228496927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 228596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 228696927adbSRichard Henderson nullify_over(ctx); 2287ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 228896927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 228996927adbSRichard Henderson return nullify_end(ctx); 229096927adbSRichard Henderson #endif 229196927adbSRichard Henderson } 2292e1b5a5edSRichard Henderson 22934a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 22944a4554c6SHelge Deller { 22954a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22964a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY 22974a4554c6SHelge Deller nullify_over(ctx); 2298ad75a51eSRichard Henderson gen_helper_getshadowregs(tcg_env); 22994a4554c6SHelge Deller return nullify_end(ctx); 23004a4554c6SHelge Deller #endif 23014a4554c6SHelge Deller } 23024a4554c6SHelge Deller 2303deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 230498a9cb79SRichard Henderson { 2305deee69a1SRichard Henderson if (a->m) { 23066fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 23076fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 23086fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 230998a9cb79SRichard Henderson 231098a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 23116fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2312deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2313deee69a1SRichard Henderson } 231498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 231531234768SRichard Henderson return true; 231698a9cb79SRichard Henderson } 231798a9cb79SRichard Henderson 2318deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 231998a9cb79SRichard Henderson { 23206fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2321eed14219SRichard Henderson TCGv_i32 level, want; 23226fd0c7bcSRichard Henderson TCGv_i64 addr; 232398a9cb79SRichard Henderson 232498a9cb79SRichard Henderson nullify_over(ctx); 232598a9cb79SRichard Henderson 2326deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2327deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2328eed14219SRichard Henderson 2329deee69a1SRichard Henderson if (a->imm) { 2330e5d487c9SRichard Henderson level = tcg_constant_i32(a->ri & 3); 233198a9cb79SRichard Henderson } else { 2332eed14219SRichard Henderson level = tcg_temp_new_i32(); 23336fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2334eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 233598a9cb79SRichard Henderson } 233629dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2337eed14219SRichard Henderson 2338ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2339eed14219SRichard Henderson 2340deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 234131234768SRichard Henderson return nullify_end(ctx); 234298a9cb79SRichard Henderson } 234398a9cb79SRichard Henderson 2344deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 23458d6ae7fbSRichard Henderson { 23468577f354SRichard Henderson if (ctx->is_pa20) { 23478577f354SRichard Henderson return false; 23488577f354SRichard Henderson } 2349deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2350deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23516fd0c7bcSRichard Henderson TCGv_i64 addr; 23526fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 23538d6ae7fbSRichard Henderson 23548d6ae7fbSRichard Henderson nullify_over(ctx); 23558d6ae7fbSRichard Henderson 2356deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2357deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2358deee69a1SRichard Henderson if (a->addr) { 23598577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 23608d6ae7fbSRichard Henderson } else { 23618577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 23628d6ae7fbSRichard Henderson } 23638d6ae7fbSRichard Henderson 236432dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 236532dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 236631234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 236731234768SRichard Henderson } 236831234768SRichard Henderson return nullify_end(ctx); 2369deee69a1SRichard Henderson #endif 23708d6ae7fbSRichard Henderson } 237163300a00SRichard Henderson 2372eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 237363300a00SRichard Henderson { 2374deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2375deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23766fd0c7bcSRichard Henderson TCGv_i64 addr; 23776fd0c7bcSRichard Henderson TCGv_i64 ofs; 237863300a00SRichard Henderson 237963300a00SRichard Henderson nullify_over(ctx); 238063300a00SRichard Henderson 2381deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2382eb25d10fSHelge Deller 2383eb25d10fSHelge Deller /* 2384eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2385eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2386eb25d10fSHelge Deller */ 2387eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2388eb25d10fSHelge Deller if (ctx->is_pa20) { 2389eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 239063300a00SRichard Henderson } 2391eb25d10fSHelge Deller 2392eb25d10fSHelge Deller if (local) { 2393eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 239463300a00SRichard Henderson } else { 2395ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 239663300a00SRichard Henderson } 239763300a00SRichard Henderson 2398eb25d10fSHelge Deller if (a->m) { 2399eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2400eb25d10fSHelge Deller } 2401eb25d10fSHelge Deller 2402eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2403eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2404eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2405eb25d10fSHelge Deller } 2406eb25d10fSHelge Deller return nullify_end(ctx); 2407eb25d10fSHelge Deller #endif 2408eb25d10fSHelge Deller } 2409eb25d10fSHelge Deller 2410eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2411eb25d10fSHelge Deller { 2412eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2413eb25d10fSHelge Deller } 2414eb25d10fSHelge Deller 2415eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2416eb25d10fSHelge Deller { 2417eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2418eb25d10fSHelge Deller } 2419eb25d10fSHelge Deller 2420eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2421eb25d10fSHelge Deller { 2422eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2423eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2424eb25d10fSHelge Deller nullify_over(ctx); 2425eb25d10fSHelge Deller 2426eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2427eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2428eb25d10fSHelge Deller 242963300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 243032dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 243131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 243231234768SRichard Henderson } 243331234768SRichard Henderson return nullify_end(ctx); 2434deee69a1SRichard Henderson #endif 243563300a00SRichard Henderson } 24362dfcca9fSRichard Henderson 24376797c315SNick Hudson /* 24386797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 24396797c315SNick Hudson * See 24406797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 24416797c315SNick Hudson * page 13-9 (195/206) 24426797c315SNick Hudson */ 24436797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 24446797c315SNick Hudson { 24458577f354SRichard Henderson if (ctx->is_pa20) { 24468577f354SRichard Henderson return false; 24478577f354SRichard Henderson } 24486797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24496797c315SNick Hudson #ifndef CONFIG_USER_ONLY 24506fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 24516fd0c7bcSRichard Henderson TCGv_i64 reg; 24526797c315SNick Hudson 24536797c315SNick Hudson nullify_over(ctx); 24546797c315SNick Hudson 24556797c315SNick Hudson /* 24566797c315SNick Hudson * FIXME: 24576797c315SNick Hudson * if (not (pcxl or pcxl2)) 24586797c315SNick Hudson * return gen_illegal(ctx); 24596797c315SNick Hudson */ 24606797c315SNick Hudson 24616fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 24626fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 24636fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 24646797c315SNick Hudson 2465ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 24666797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 24676797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2468ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 24696797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 24706797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 24716797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2472d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 24736797c315SNick Hudson 24746797c315SNick Hudson reg = load_gpr(ctx, a->r); 24756797c315SNick Hudson if (a->addr) { 24768577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 24776797c315SNick Hudson } else { 24788577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 24796797c315SNick Hudson } 24806797c315SNick Hudson 24816797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 24826797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 24836797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24846797c315SNick Hudson } 24856797c315SNick Hudson return nullify_end(ctx); 24866797c315SNick Hudson #endif 24876797c315SNick Hudson } 24886797c315SNick Hudson 24898577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 24908577f354SRichard Henderson { 24918577f354SRichard Henderson if (!ctx->is_pa20) { 24928577f354SRichard Henderson return false; 24938577f354SRichard Henderson } 24948577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24958577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 24968577f354SRichard Henderson nullify_over(ctx); 24978577f354SRichard Henderson { 24988577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 24998577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 25008577f354SRichard Henderson 25018577f354SRichard Henderson if (a->data) { 25028577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 25038577f354SRichard Henderson } else { 25048577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 25058577f354SRichard Henderson } 25068577f354SRichard Henderson } 25078577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 25088577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 25098577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 25108577f354SRichard Henderson } 25118577f354SRichard Henderson return nullify_end(ctx); 25128577f354SRichard Henderson #endif 25138577f354SRichard Henderson } 25148577f354SRichard Henderson 2515deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 25162dfcca9fSRichard Henderson { 2517deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2518deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 25196fd0c7bcSRichard Henderson TCGv_i64 vaddr; 25206fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 25212dfcca9fSRichard Henderson 25222dfcca9fSRichard Henderson nullify_over(ctx); 25232dfcca9fSRichard Henderson 2524deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 25252dfcca9fSRichard Henderson 2526aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2527ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 25282dfcca9fSRichard Henderson 25292dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2530deee69a1SRichard Henderson if (a->m) { 2531deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 25322dfcca9fSRichard Henderson } 2533deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 25342dfcca9fSRichard Henderson 253531234768SRichard Henderson return nullify_end(ctx); 2536deee69a1SRichard Henderson #endif 25372dfcca9fSRichard Henderson } 253843a97b81SRichard Henderson 2539deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 254043a97b81SRichard Henderson { 254143a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 254243a97b81SRichard Henderson 254343a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 254443a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 254543a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 254643a97b81SRichard Henderson since the entire address space is coherent. */ 2547a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 254843a97b81SRichard Henderson 254931234768SRichard Henderson cond_free(&ctx->null_cond); 255031234768SRichard Henderson return true; 255143a97b81SRichard Henderson } 255298a9cb79SRichard Henderson 2553faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2554b2167459SRichard Henderson { 25550c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2556b2167459SRichard Henderson } 2557b2167459SRichard Henderson 2558faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2559b2167459SRichard Henderson { 25600c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2561b2167459SRichard Henderson } 2562b2167459SRichard Henderson 2563faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2564b2167459SRichard Henderson { 25650c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2566b2167459SRichard Henderson } 2567b2167459SRichard Henderson 2568faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2569b2167459SRichard Henderson { 25700c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 25710c982a28SRichard Henderson } 2572b2167459SRichard Henderson 2573faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 25740c982a28SRichard Henderson { 25750c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 25760c982a28SRichard Henderson } 25770c982a28SRichard Henderson 257863c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 25790c982a28SRichard Henderson { 25800c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 25810c982a28SRichard Henderson } 25820c982a28SRichard Henderson 258363c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25840c982a28SRichard Henderson { 25850c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 25860c982a28SRichard Henderson } 25870c982a28SRichard Henderson 258863c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25890c982a28SRichard Henderson { 25900c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 25910c982a28SRichard Henderson } 25920c982a28SRichard Henderson 259363c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25940c982a28SRichard Henderson { 25950c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 25960c982a28SRichard Henderson } 25970c982a28SRichard Henderson 259863c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 25990c982a28SRichard Henderson { 26000c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 26010c982a28SRichard Henderson } 26020c982a28SRichard Henderson 260363c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 26040c982a28SRichard Henderson { 26050c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 26060c982a28SRichard Henderson } 26070c982a28SRichard Henderson 2608fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 26090c982a28SRichard Henderson { 26106fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 26110c982a28SRichard Henderson } 26120c982a28SRichard Henderson 2613fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 26140c982a28SRichard Henderson { 26156fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 26160c982a28SRichard Henderson } 26170c982a28SRichard Henderson 2618fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 26190c982a28SRichard Henderson { 26200c982a28SRichard Henderson if (a->cf == 0) { 26210c982a28SRichard Henderson unsigned r2 = a->r2; 26220c982a28SRichard Henderson unsigned r1 = a->r1; 26230c982a28SRichard Henderson unsigned rt = a->t; 26240c982a28SRichard Henderson 26257aee8189SRichard Henderson if (rt == 0) { /* NOP */ 26267aee8189SRichard Henderson cond_free(&ctx->null_cond); 26277aee8189SRichard Henderson return true; 26287aee8189SRichard Henderson } 26297aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2630b2167459SRichard Henderson if (r1 == 0) { 26316fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 26326fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2633b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2634b2167459SRichard Henderson } else { 2635b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2636b2167459SRichard Henderson } 2637b2167459SRichard Henderson cond_free(&ctx->null_cond); 263831234768SRichard Henderson return true; 2639b2167459SRichard Henderson } 26407aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 26417aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 26427aee8189SRichard Henderson * 26437aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 26447aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 26457aee8189SRichard Henderson * currently implemented as idle. 26467aee8189SRichard Henderson */ 26477aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 26487aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 26497aee8189SRichard Henderson until the next timer interrupt. */ 26507aee8189SRichard Henderson nullify_over(ctx); 26517aee8189SRichard Henderson 26527aee8189SRichard Henderson /* Advance the instruction queue. */ 2653741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 2654741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 26557aee8189SRichard Henderson nullify_set(ctx, 0); 26567aee8189SRichard Henderson 26577aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2658ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 265929dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 26607aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 26617aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 26627aee8189SRichard Henderson 26637aee8189SRichard Henderson return nullify_end(ctx); 26647aee8189SRichard Henderson } 26657aee8189SRichard Henderson #endif 26667aee8189SRichard Henderson } 26676fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 26687aee8189SRichard Henderson } 2669b2167459SRichard Henderson 2670fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2671b2167459SRichard Henderson { 26726fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 26730c982a28SRichard Henderson } 26740c982a28SRichard Henderson 2675345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 26760c982a28SRichard Henderson { 26776fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2678b2167459SRichard Henderson 26790c982a28SRichard Henderson if (a->cf) { 2680b2167459SRichard Henderson nullify_over(ctx); 2681b2167459SRichard Henderson } 26820c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26830c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2684345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 268531234768SRichard Henderson return nullify_end(ctx); 2686b2167459SRichard Henderson } 2687b2167459SRichard Henderson 2688af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2689b2167459SRichard Henderson { 26906fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2691b2167459SRichard Henderson 26920c982a28SRichard Henderson if (a->cf) { 2693b2167459SRichard Henderson nullify_over(ctx); 2694b2167459SRichard Henderson } 26950c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26960c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 26976fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64); 269831234768SRichard Henderson return nullify_end(ctx); 2699b2167459SRichard Henderson } 2700b2167459SRichard Henderson 2701af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2702b2167459SRichard Henderson { 27036fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2704b2167459SRichard Henderson 27050c982a28SRichard Henderson if (a->cf) { 2706b2167459SRichard Henderson nullify_over(ctx); 2707b2167459SRichard Henderson } 27080c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 27090c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2710aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 27116fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 27126fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64); 271331234768SRichard Henderson return nullify_end(ctx); 2714b2167459SRichard Henderson } 2715b2167459SRichard Henderson 2716af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2717b2167459SRichard Henderson { 27180c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 27190c982a28SRichard Henderson } 27200c982a28SRichard Henderson 2721af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 27220c982a28SRichard Henderson { 27230c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 27240c982a28SRichard Henderson } 27250c982a28SRichard Henderson 2726af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 27270c982a28SRichard Henderson { 27286fd0c7bcSRichard Henderson TCGv_i64 tmp; 2729b2167459SRichard Henderson 2730b2167459SRichard Henderson nullify_over(ctx); 2731b2167459SRichard Henderson 2732aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 27336fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, cpu_psw_cb, 3); 2734b2167459SRichard Henderson if (!is_i) { 27356fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2736b2167459SRichard Henderson } 27376fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 27386fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 2739af240753SRichard Henderson do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false, 27406fd0c7bcSRichard Henderson is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64); 274131234768SRichard Henderson return nullify_end(ctx); 2742b2167459SRichard Henderson } 2743b2167459SRichard Henderson 2744af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2745b2167459SRichard Henderson { 27460c982a28SRichard Henderson return do_dcor(ctx, a, false); 27470c982a28SRichard Henderson } 27480c982a28SRichard Henderson 2749af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 27500c982a28SRichard Henderson { 27510c982a28SRichard Henderson return do_dcor(ctx, a, true); 27520c982a28SRichard Henderson } 27530c982a28SRichard Henderson 27540c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 27550c982a28SRichard Henderson { 2756a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 27576fd0c7bcSRichard Henderson TCGv_i64 cout; 2758b2167459SRichard Henderson 2759b2167459SRichard Henderson nullify_over(ctx); 2760b2167459SRichard Henderson 27610c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 27620c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2763b2167459SRichard Henderson 2764aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2765aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2766aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2767aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2768b2167459SRichard Henderson 2769b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 27706fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 27716fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2772b2167459SRichard Henderson 277372ca8753SRichard Henderson /* 277472ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 277572ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 277672ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 277772ca8753SRichard Henderson * proper inputs to the addition without movcond. 277872ca8753SRichard Henderson */ 27796fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 27806fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 27816fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 278272ca8753SRichard Henderson 2783a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2784a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2785a4db4a78SRichard Henderson addc, ctx->zero); 2786b2167459SRichard Henderson 2787b2167459SRichard Henderson /* Write back the result register. */ 27880c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2789b2167459SRichard Henderson 2790b2167459SRichard Henderson /* Write back PSW[CB]. */ 27916fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 27926fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2793b2167459SRichard Henderson 2794b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 279572ca8753SRichard Henderson cout = get_psw_carry(ctx, false); 27966fd0c7bcSRichard Henderson tcg_gen_neg_i64(cpu_psw_v, cout); 27976fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2798b2167459SRichard Henderson 2799b2167459SRichard Henderson /* Install the new nullification. */ 28000c982a28SRichard Henderson if (a->cf) { 28016fd0c7bcSRichard Henderson TCGv_i64 sv = NULL; 2802b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2803b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 2804b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 2805b2167459SRichard Henderson } 2806a751eb31SRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv); 2807b2167459SRichard Henderson } 2808b2167459SRichard Henderson 280931234768SRichard Henderson return nullify_end(ctx); 2810b2167459SRichard Henderson } 2811b2167459SRichard Henderson 28120588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2813b2167459SRichard Henderson { 28140588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 28150588e061SRichard Henderson } 28160588e061SRichard Henderson 28170588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 28180588e061SRichard Henderson { 28190588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 28200588e061SRichard Henderson } 28210588e061SRichard Henderson 28220588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 28230588e061SRichard Henderson { 28240588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 28250588e061SRichard Henderson } 28260588e061SRichard Henderson 28270588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 28280588e061SRichard Henderson { 28290588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 28300588e061SRichard Henderson } 28310588e061SRichard Henderson 28320588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 28330588e061SRichard Henderson { 28340588e061SRichard Henderson return do_sub_imm(ctx, a, false); 28350588e061SRichard Henderson } 28360588e061SRichard Henderson 28370588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 28380588e061SRichard Henderson { 28390588e061SRichard Henderson return do_sub_imm(ctx, a, true); 28400588e061SRichard Henderson } 28410588e061SRichard Henderson 2842345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 28430588e061SRichard Henderson { 28446fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 2845b2167459SRichard Henderson 28460588e061SRichard Henderson if (a->cf) { 2847b2167459SRichard Henderson nullify_over(ctx); 2848b2167459SRichard Henderson } 2849b2167459SRichard Henderson 28506fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 28510588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 2852345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2853b2167459SRichard Henderson 285431234768SRichard Henderson return nullify_end(ctx); 2855b2167459SRichard Henderson } 2856b2167459SRichard Henderson 28570843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 28580843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 28590843563fSRichard Henderson { 28600843563fSRichard Henderson TCGv_i64 r1, r2, dest; 28610843563fSRichard Henderson 28620843563fSRichard Henderson if (!ctx->is_pa20) { 28630843563fSRichard Henderson return false; 28640843563fSRichard Henderson } 28650843563fSRichard Henderson 28660843563fSRichard Henderson nullify_over(ctx); 28670843563fSRichard Henderson 28680843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 28690843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 28700843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 28710843563fSRichard Henderson 28720843563fSRichard Henderson fn(dest, r1, r2); 28730843563fSRichard Henderson save_gpr(ctx, a->t, dest); 28740843563fSRichard Henderson 28750843563fSRichard Henderson return nullify_end(ctx); 28760843563fSRichard Henderson } 28770843563fSRichard Henderson 2878151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 2879151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 2880151f309bSRichard Henderson { 2881151f309bSRichard Henderson TCGv_i64 r, dest; 2882151f309bSRichard Henderson 2883151f309bSRichard Henderson if (!ctx->is_pa20) { 2884151f309bSRichard Henderson return false; 2885151f309bSRichard Henderson } 2886151f309bSRichard Henderson 2887151f309bSRichard Henderson nullify_over(ctx); 2888151f309bSRichard Henderson 2889151f309bSRichard Henderson r = load_gpr(ctx, a->r); 2890151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 2891151f309bSRichard Henderson 2892151f309bSRichard Henderson fn(dest, r, a->i); 2893151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 2894151f309bSRichard Henderson 2895151f309bSRichard Henderson return nullify_end(ctx); 2896151f309bSRichard Henderson } 2897151f309bSRichard Henderson 28983bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 28993bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 29003bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 29013bbb8e48SRichard Henderson { 29023bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 29033bbb8e48SRichard Henderson 29043bbb8e48SRichard Henderson if (!ctx->is_pa20) { 29053bbb8e48SRichard Henderson return false; 29063bbb8e48SRichard Henderson } 29073bbb8e48SRichard Henderson 29083bbb8e48SRichard Henderson nullify_over(ctx); 29093bbb8e48SRichard Henderson 29103bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 29113bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 29123bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 29133bbb8e48SRichard Henderson 29143bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 29153bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 29163bbb8e48SRichard Henderson 29173bbb8e48SRichard Henderson return nullify_end(ctx); 29183bbb8e48SRichard Henderson } 29193bbb8e48SRichard Henderson 29200843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 29210843563fSRichard Henderson { 29220843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 29230843563fSRichard Henderson } 29240843563fSRichard Henderson 29250843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 29260843563fSRichard Henderson { 29270843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 29280843563fSRichard Henderson } 29290843563fSRichard Henderson 29300843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 29310843563fSRichard Henderson { 29320843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 29330843563fSRichard Henderson } 29340843563fSRichard Henderson 29351b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 29361b3cb7c8SRichard Henderson { 29371b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 29381b3cb7c8SRichard Henderson } 29391b3cb7c8SRichard Henderson 2940151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 2941151f309bSRichard Henderson { 2942151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 2943151f309bSRichard Henderson } 2944151f309bSRichard Henderson 2945151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 2946151f309bSRichard Henderson { 2947151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 2948151f309bSRichard Henderson } 2949151f309bSRichard Henderson 2950151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 2951151f309bSRichard Henderson { 2952151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 2953151f309bSRichard Henderson } 2954151f309bSRichard Henderson 29553bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 29563bbb8e48SRichard Henderson { 29573bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 29583bbb8e48SRichard Henderson } 29593bbb8e48SRichard Henderson 29603bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 29613bbb8e48SRichard Henderson { 29623bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 29633bbb8e48SRichard Henderson } 29643bbb8e48SRichard Henderson 296510c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 296610c9e58dSRichard Henderson { 296710c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 296810c9e58dSRichard Henderson } 296910c9e58dSRichard Henderson 297010c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 297110c9e58dSRichard Henderson { 297210c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 297310c9e58dSRichard Henderson } 297410c9e58dSRichard Henderson 297510c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 297610c9e58dSRichard Henderson { 297710c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 297810c9e58dSRichard Henderson } 297910c9e58dSRichard Henderson 2980c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2981c2a7ee3fSRichard Henderson { 2982c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 2983c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2984c2a7ee3fSRichard Henderson 2985c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 2986c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 2987c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 2988c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2989c2a7ee3fSRichard Henderson } 2990c2a7ee3fSRichard Henderson 2991c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 2992c2a7ee3fSRichard Henderson { 2993c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 2994c2a7ee3fSRichard Henderson } 2995c2a7ee3fSRichard Henderson 2996c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2997c2a7ee3fSRichard Henderson { 2998c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 2999c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3000c2a7ee3fSRichard Henderson 3001c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 3002c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 3003c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 3004c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3005c2a7ee3fSRichard Henderson } 3006c2a7ee3fSRichard Henderson 3007c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 3008c2a7ee3fSRichard Henderson { 3009c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 3010c2a7ee3fSRichard Henderson } 3011c2a7ee3fSRichard Henderson 3012c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3013c2a7ee3fSRichard Henderson { 3014c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3015c2a7ee3fSRichard Henderson 3016c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 3017c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 3018c2a7ee3fSRichard Henderson } 3019c2a7ee3fSRichard Henderson 3020c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 3021c2a7ee3fSRichard Henderson { 3022c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 3023c2a7ee3fSRichard Henderson } 3024c2a7ee3fSRichard Henderson 3025c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3026c2a7ee3fSRichard Henderson { 3027c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 3028c2a7ee3fSRichard Henderson } 3029c2a7ee3fSRichard Henderson 3030c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 3031c2a7ee3fSRichard Henderson { 3032c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 3033c2a7ee3fSRichard Henderson } 3034c2a7ee3fSRichard Henderson 30354e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 30364e7abdb1SRichard Henderson { 30374e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 30384e7abdb1SRichard Henderson 30394e7abdb1SRichard Henderson if (!ctx->is_pa20) { 30404e7abdb1SRichard Henderson return false; 30414e7abdb1SRichard Henderson } 30424e7abdb1SRichard Henderson 30434e7abdb1SRichard Henderson nullify_over(ctx); 30444e7abdb1SRichard Henderson 30454e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 30464e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 30474e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 30484e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 30494e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 30504e7abdb1SRichard Henderson 30514e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 30524e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 30534e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 30544e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 30554e7abdb1SRichard Henderson 30564e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 30574e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 30584e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 30594e7abdb1SRichard Henderson 30604e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 30614e7abdb1SRichard Henderson return nullify_end(ctx); 30624e7abdb1SRichard Henderson } 30634e7abdb1SRichard Henderson 30641cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 306596d6407fSRichard Henderson { 3066b5caa17cSRichard Henderson if (ctx->is_pa20) { 3067b5caa17cSRichard Henderson /* 3068b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3069b5caa17cSRichard Henderson * Any base modification still occurs. 3070b5caa17cSRichard Henderson */ 3071b5caa17cSRichard Henderson if (a->t == 0) { 3072b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3073b5caa17cSRichard Henderson } 3074b5caa17cSRichard Henderson } else if (a->size > MO_32) { 30750786a3b6SHelge Deller return gen_illegal(ctx); 3076c53e401eSRichard Henderson } 30771cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 30781cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 307996d6407fSRichard Henderson } 308096d6407fSRichard Henderson 30811cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 308296d6407fSRichard Henderson { 30831cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3084c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 30850786a3b6SHelge Deller return gen_illegal(ctx); 308696d6407fSRichard Henderson } 3087c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 30880786a3b6SHelge Deller } 308996d6407fSRichard Henderson 30901cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 309196d6407fSRichard Henderson { 3092b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3093a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 30946fd0c7bcSRichard Henderson TCGv_i64 addr; 309596d6407fSRichard Henderson 3096c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 309751416c4eSRichard Henderson return gen_illegal(ctx); 309851416c4eSRichard Henderson } 309951416c4eSRichard Henderson 310096d6407fSRichard Henderson nullify_over(ctx); 310196d6407fSRichard Henderson 31021cd012a5SRichard Henderson if (a->m) { 310386f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 310486f8d05fSRichard Henderson we see the result of the load. */ 3105aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 310696d6407fSRichard Henderson } else { 31071cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 310896d6407fSRichard Henderson } 310996d6407fSRichard Henderson 31101cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0, 311117fe594cSRichard Henderson a->disp, a->sp, a->m, MMU_DISABLED(ctx)); 3112b1af755cSRichard Henderson 3113b1af755cSRichard Henderson /* 3114b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3115b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3116b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3117b1af755cSRichard Henderson * 3118b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3119b1af755cSRichard Henderson * with the ,co completer. 3120b1af755cSRichard Henderson */ 3121b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3122b1af755cSRichard Henderson 3123a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3124b1af755cSRichard Henderson 31251cd012a5SRichard Henderson if (a->m) { 31261cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 312796d6407fSRichard Henderson } 31281cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 312996d6407fSRichard Henderson 313031234768SRichard Henderson return nullify_end(ctx); 313196d6407fSRichard Henderson } 313296d6407fSRichard Henderson 31331cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 313496d6407fSRichard Henderson { 31356fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31366fd0c7bcSRichard Henderson TCGv_i64 addr; 313796d6407fSRichard Henderson 313896d6407fSRichard Henderson nullify_over(ctx); 313996d6407fSRichard Henderson 31401cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 314117fe594cSRichard Henderson MMU_DISABLED(ctx)); 31421cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 31431cd012a5SRichard Henderson if (a->a) { 3144f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3145ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3146f9f46db4SEmilio G. Cota } else { 3147ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3148f9f46db4SEmilio G. Cota } 3149f9f46db4SEmilio G. Cota } else { 3150f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3151ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 315296d6407fSRichard Henderson } else { 3153ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 315496d6407fSRichard Henderson } 3155f9f46db4SEmilio G. Cota } 31561cd012a5SRichard Henderson if (a->m) { 31576fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 31581cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 315996d6407fSRichard Henderson } 316096d6407fSRichard Henderson 316131234768SRichard Henderson return nullify_end(ctx); 316296d6407fSRichard Henderson } 316396d6407fSRichard Henderson 316425460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 316525460fc5SRichard Henderson { 31666fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31676fd0c7bcSRichard Henderson TCGv_i64 addr; 316825460fc5SRichard Henderson 316925460fc5SRichard Henderson if (!ctx->is_pa20) { 317025460fc5SRichard Henderson return false; 317125460fc5SRichard Henderson } 317225460fc5SRichard Henderson nullify_over(ctx); 317325460fc5SRichard Henderson 317425460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 317517fe594cSRichard Henderson MMU_DISABLED(ctx)); 317625460fc5SRichard Henderson val = load_gpr(ctx, a->r); 317725460fc5SRichard Henderson if (a->a) { 317825460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 317925460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 318025460fc5SRichard Henderson } else { 318125460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 318225460fc5SRichard Henderson } 318325460fc5SRichard Henderson } else { 318425460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 318525460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 318625460fc5SRichard Henderson } else { 318725460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 318825460fc5SRichard Henderson } 318925460fc5SRichard Henderson } 319025460fc5SRichard Henderson if (a->m) { 31916fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 319225460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 319325460fc5SRichard Henderson } 319425460fc5SRichard Henderson 319525460fc5SRichard Henderson return nullify_end(ctx); 319625460fc5SRichard Henderson } 319725460fc5SRichard Henderson 31981cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3199d0a851ccSRichard Henderson { 3200d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3201d0a851ccSRichard Henderson 3202d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3203451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 32041cd012a5SRichard Henderson trans_ld(ctx, a); 3205d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 320631234768SRichard Henderson return true; 3207d0a851ccSRichard Henderson } 3208d0a851ccSRichard Henderson 32091cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3210d0a851ccSRichard Henderson { 3211d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3212d0a851ccSRichard Henderson 3213d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3214451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 32151cd012a5SRichard Henderson trans_st(ctx, a); 3216d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 321731234768SRichard Henderson return true; 3218d0a851ccSRichard Henderson } 321995412a61SRichard Henderson 32200588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3221b2167459SRichard Henderson { 32226fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3223b2167459SRichard Henderson 32246fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 32250588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3226b2167459SRichard Henderson cond_free(&ctx->null_cond); 322731234768SRichard Henderson return true; 3228b2167459SRichard Henderson } 3229b2167459SRichard Henderson 32300588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3231b2167459SRichard Henderson { 32326fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 32336fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3234b2167459SRichard Henderson 32356fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3236b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3237b2167459SRichard Henderson cond_free(&ctx->null_cond); 323831234768SRichard Henderson return true; 3239b2167459SRichard Henderson } 3240b2167459SRichard Henderson 32410588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3242b2167459SRichard Henderson { 32436fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3244b2167459SRichard Henderson 3245b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3246d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 32470588e061SRichard Henderson if (a->b == 0) { 32486fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3249b2167459SRichard Henderson } else { 32506fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3251b2167459SRichard Henderson } 32520588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3253b2167459SRichard Henderson cond_free(&ctx->null_cond); 325431234768SRichard Henderson return true; 3255b2167459SRichard Henderson } 3256b2167459SRichard Henderson 32576fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3258e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 325998cd9ca7SRichard Henderson { 32606fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 326198cd9ca7SRichard Henderson DisasCond cond; 326298cd9ca7SRichard Henderson 326398cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3264aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 326598cd9ca7SRichard Henderson 32666fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 326798cd9ca7SRichard Henderson 3268f764718dSRichard Henderson sv = NULL; 3269b47a4a02SSven Schnelle if (cond_need_sv(c)) { 327098cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 327198cd9ca7SRichard Henderson } 327298cd9ca7SRichard Henderson 32734fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 327401afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 327598cd9ca7SRichard Henderson } 327698cd9ca7SRichard Henderson 327701afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 327898cd9ca7SRichard Henderson { 3279e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3280e9efd4bcSRichard Henderson return false; 3281e9efd4bcSRichard Henderson } 328201afb7beSRichard Henderson nullify_over(ctx); 3283e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3284e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 328501afb7beSRichard Henderson } 328601afb7beSRichard Henderson 328701afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 328801afb7beSRichard Henderson { 3289c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3290c65c3ee1SRichard Henderson return false; 3291c65c3ee1SRichard Henderson } 329201afb7beSRichard Henderson nullify_over(ctx); 32936fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3294c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 329501afb7beSRichard Henderson } 329601afb7beSRichard Henderson 32976fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 329801afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 329901afb7beSRichard Henderson { 33006fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 330198cd9ca7SRichard Henderson DisasCond cond; 3302bdcccc17SRichard Henderson bool d = false; 330398cd9ca7SRichard Henderson 3304f25d3160SRichard Henderson /* 3305f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3306f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3307f25d3160SRichard Henderson */ 3308f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3309f25d3160SRichard Henderson d = c >= 5; 3310f25d3160SRichard Henderson if (d) { 3311f25d3160SRichard Henderson c &= 3; 3312f25d3160SRichard Henderson } 3313f25d3160SRichard Henderson } 3314f25d3160SRichard Henderson 331598cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3316aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3317f764718dSRichard Henderson sv = NULL; 3318bdcccc17SRichard Henderson cb_cond = NULL; 331998cd9ca7SRichard Henderson 3320b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3321aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3322aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3323bdcccc17SRichard Henderson 33246fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 33256fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 33266fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 33276fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3328bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3329b47a4a02SSven Schnelle } else { 33306fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3331b47a4a02SSven Schnelle } 3332b47a4a02SSven Schnelle if (cond_need_sv(c)) { 333398cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 333498cd9ca7SRichard Henderson } 333598cd9ca7SRichard Henderson 3336a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 333743675d20SSven Schnelle save_gpr(ctx, r, dest); 333801afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 333998cd9ca7SRichard Henderson } 334098cd9ca7SRichard Henderson 334101afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 334298cd9ca7SRichard Henderson { 334301afb7beSRichard Henderson nullify_over(ctx); 334401afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 334501afb7beSRichard Henderson } 334601afb7beSRichard Henderson 334701afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 334801afb7beSRichard Henderson { 334901afb7beSRichard Henderson nullify_over(ctx); 33506fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 335101afb7beSRichard Henderson } 335201afb7beSRichard Henderson 335301afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 335401afb7beSRichard Henderson { 33556fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 335698cd9ca7SRichard Henderson DisasCond cond; 335798cd9ca7SRichard Henderson 335898cd9ca7SRichard Henderson nullify_over(ctx); 335998cd9ca7SRichard Henderson 3360aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 336101afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 336284e224d4SRichard Henderson if (cond_need_ext(ctx, a->d)) { 33631e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 33646fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 33656fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 33661e9ab9fbSRichard Henderson } else { 33676fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 33681e9ab9fbSRichard Henderson } 336998cd9ca7SRichard Henderson 33701e9ab9fbSRichard Henderson cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 337101afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 337298cd9ca7SRichard Henderson } 337398cd9ca7SRichard Henderson 337401afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 337598cd9ca7SRichard Henderson { 33766fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 337701afb7beSRichard Henderson DisasCond cond; 33781e9ab9fbSRichard Henderson int p; 337901afb7beSRichard Henderson 338001afb7beSRichard Henderson nullify_over(ctx); 338101afb7beSRichard Henderson 3382aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 338301afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 338484e224d4SRichard Henderson p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0); 33856fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, tcg_r, p); 338601afb7beSRichard Henderson 338701afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 338801afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 338901afb7beSRichard Henderson } 339001afb7beSRichard Henderson 339101afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 339201afb7beSRichard Henderson { 33936fd0c7bcSRichard Henderson TCGv_i64 dest; 339498cd9ca7SRichard Henderson DisasCond cond; 339598cd9ca7SRichard Henderson 339698cd9ca7SRichard Henderson nullify_over(ctx); 339798cd9ca7SRichard Henderson 339801afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 339901afb7beSRichard Henderson if (a->r1 == 0) { 34006fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 340198cd9ca7SRichard Henderson } else { 34026fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 340398cd9ca7SRichard Henderson } 340498cd9ca7SRichard Henderson 34054fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 34064fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 340701afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 340801afb7beSRichard Henderson } 340901afb7beSRichard Henderson 341001afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 341101afb7beSRichard Henderson { 34126fd0c7bcSRichard Henderson TCGv_i64 dest; 341301afb7beSRichard Henderson DisasCond cond; 341401afb7beSRichard Henderson 341501afb7beSRichard Henderson nullify_over(ctx); 341601afb7beSRichard Henderson 341701afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 34186fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 341901afb7beSRichard Henderson 34204fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 34214fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 342201afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 342398cd9ca7SRichard Henderson } 342498cd9ca7SRichard Henderson 3425f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 34260b1347d2SRichard Henderson { 34276fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 34280b1347d2SRichard Henderson 3429f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3430f7b775a9SRichard Henderson return false; 3431f7b775a9SRichard Henderson } 343230878590SRichard Henderson if (a->c) { 34330b1347d2SRichard Henderson nullify_over(ctx); 34340b1347d2SRichard Henderson } 34350b1347d2SRichard Henderson 343630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3437f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 343830878590SRichard Henderson if (a->r1 == 0) { 3439f7b775a9SRichard Henderson if (a->d) { 34406fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3441f7b775a9SRichard Henderson } else { 3442aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3443f7b775a9SRichard Henderson 34446fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 34456fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 34466fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3447f7b775a9SRichard Henderson } 344830878590SRichard Henderson } else if (a->r1 == a->r2) { 3449f7b775a9SRichard Henderson if (a->d) { 34506fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3451f7b775a9SRichard Henderson } else { 34520b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3453e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3454e1d635e8SRichard Henderson 34556fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 34566fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3457f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3458e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 34596fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3460f7b775a9SRichard Henderson } 3461f7b775a9SRichard Henderson } else { 34626fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3463f7b775a9SRichard Henderson 3464f7b775a9SRichard Henderson if (a->d) { 3465aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3466aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3467f7b775a9SRichard Henderson 34686fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 3469a01491a2SHelge Deller tcg_gen_shl_i64(t, src1, n); 34706fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 3471a01491a2SHelge Deller tcg_gen_shr_i64(dest, src2, cpu_sar); 34726fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 34730b1347d2SRichard Henderson } else { 34740b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 34750b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 34760b1347d2SRichard Henderson 34776fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3478967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3479967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 34800b1347d2SRichard Henderson } 3481f7b775a9SRichard Henderson } 348230878590SRichard Henderson save_gpr(ctx, a->t, dest); 34830b1347d2SRichard Henderson 34840b1347d2SRichard Henderson /* Install the new nullification. */ 34850b1347d2SRichard Henderson cond_free(&ctx->null_cond); 348630878590SRichard Henderson if (a->c) { 34874fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 34880b1347d2SRichard Henderson } 348931234768SRichard Henderson return nullify_end(ctx); 34900b1347d2SRichard Henderson } 34910b1347d2SRichard Henderson 3492f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 34930b1347d2SRichard Henderson { 3494f7b775a9SRichard Henderson unsigned width, sa; 34956fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 34960b1347d2SRichard Henderson 3497f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3498f7b775a9SRichard Henderson return false; 3499f7b775a9SRichard Henderson } 350030878590SRichard Henderson if (a->c) { 35010b1347d2SRichard Henderson nullify_over(ctx); 35020b1347d2SRichard Henderson } 35030b1347d2SRichard Henderson 3504f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3505f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3506f7b775a9SRichard Henderson 350730878590SRichard Henderson dest = dest_gpr(ctx, a->t); 350830878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 350905bfd4dbSRichard Henderson if (a->r1 == 0) { 35106fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3511c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 35126fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3513f7b775a9SRichard Henderson } else { 3514f7b775a9SRichard Henderson assert(!a->d); 3515f7b775a9SRichard Henderson if (a->r1 == a->r2) { 35160b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 35176fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 35180b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 35196fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 35200b1347d2SRichard Henderson } else { 3521967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3522967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 35230b1347d2SRichard Henderson } 3524f7b775a9SRichard Henderson } 352530878590SRichard Henderson save_gpr(ctx, a->t, dest); 35260b1347d2SRichard Henderson 35270b1347d2SRichard Henderson /* Install the new nullification. */ 35280b1347d2SRichard Henderson cond_free(&ctx->null_cond); 352930878590SRichard Henderson if (a->c) { 35304fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 35310b1347d2SRichard Henderson } 353231234768SRichard Henderson return nullify_end(ctx); 35330b1347d2SRichard Henderson } 35340b1347d2SRichard Henderson 3535bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 35360b1347d2SRichard Henderson { 3537bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 35386fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 35390b1347d2SRichard Henderson 3540bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3541bd792da3SRichard Henderson return false; 3542bd792da3SRichard Henderson } 354330878590SRichard Henderson if (a->c) { 35440b1347d2SRichard Henderson nullify_over(ctx); 35450b1347d2SRichard Henderson } 35460b1347d2SRichard Henderson 354730878590SRichard Henderson dest = dest_gpr(ctx, a->t); 354830878590SRichard Henderson src = load_gpr(ctx, a->r); 3549aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 35500b1347d2SRichard Henderson 35510b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 35526fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 35536fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3554d781cb77SRichard Henderson 355530878590SRichard Henderson if (a->se) { 3556bd792da3SRichard Henderson if (!a->d) { 35576fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3558bd792da3SRichard Henderson src = dest; 3559bd792da3SRichard Henderson } 35606fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 35616fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 35620b1347d2SRichard Henderson } else { 3563bd792da3SRichard Henderson if (!a->d) { 35646fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3565bd792da3SRichard Henderson src = dest; 3566bd792da3SRichard Henderson } 35676fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 35686fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 35690b1347d2SRichard Henderson } 357030878590SRichard Henderson save_gpr(ctx, a->t, dest); 35710b1347d2SRichard Henderson 35720b1347d2SRichard Henderson /* Install the new nullification. */ 35730b1347d2SRichard Henderson cond_free(&ctx->null_cond); 357430878590SRichard Henderson if (a->c) { 3575bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35760b1347d2SRichard Henderson } 357731234768SRichard Henderson return nullify_end(ctx); 35780b1347d2SRichard Henderson } 35790b1347d2SRichard Henderson 3580bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 35810b1347d2SRichard Henderson { 3582bd792da3SRichard Henderson unsigned len, cpos, width; 35836fd0c7bcSRichard Henderson TCGv_i64 dest, src; 35840b1347d2SRichard Henderson 3585bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3586bd792da3SRichard Henderson return false; 3587bd792da3SRichard Henderson } 358830878590SRichard Henderson if (a->c) { 35890b1347d2SRichard Henderson nullify_over(ctx); 35900b1347d2SRichard Henderson } 35910b1347d2SRichard Henderson 3592bd792da3SRichard Henderson len = a->len; 3593bd792da3SRichard Henderson width = a->d ? 64 : 32; 3594bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3595bd792da3SRichard Henderson if (cpos + len > width) { 3596bd792da3SRichard Henderson len = width - cpos; 3597bd792da3SRichard Henderson } 3598bd792da3SRichard Henderson 359930878590SRichard Henderson dest = dest_gpr(ctx, a->t); 360030878590SRichard Henderson src = load_gpr(ctx, a->r); 360130878590SRichard Henderson if (a->se) { 36026fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 36030b1347d2SRichard Henderson } else { 36046fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 36050b1347d2SRichard Henderson } 360630878590SRichard Henderson save_gpr(ctx, a->t, dest); 36070b1347d2SRichard Henderson 36080b1347d2SRichard Henderson /* Install the new nullification. */ 36090b1347d2SRichard Henderson cond_free(&ctx->null_cond); 361030878590SRichard Henderson if (a->c) { 3611bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36120b1347d2SRichard Henderson } 361331234768SRichard Henderson return nullify_end(ctx); 36140b1347d2SRichard Henderson } 36150b1347d2SRichard Henderson 361672ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 36170b1347d2SRichard Henderson { 361872ae4f2bSRichard Henderson unsigned len, width; 3619c53e401eSRichard Henderson uint64_t mask0, mask1; 36206fd0c7bcSRichard Henderson TCGv_i64 dest; 36210b1347d2SRichard Henderson 362272ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 362372ae4f2bSRichard Henderson return false; 362472ae4f2bSRichard Henderson } 362530878590SRichard Henderson if (a->c) { 36260b1347d2SRichard Henderson nullify_over(ctx); 36270b1347d2SRichard Henderson } 362872ae4f2bSRichard Henderson 362972ae4f2bSRichard Henderson len = a->len; 363072ae4f2bSRichard Henderson width = a->d ? 64 : 32; 363172ae4f2bSRichard Henderson if (a->cpos + len > width) { 363272ae4f2bSRichard Henderson len = width - a->cpos; 36330b1347d2SRichard Henderson } 36340b1347d2SRichard Henderson 363530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 363630878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 363730878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 36380b1347d2SRichard Henderson 363930878590SRichard Henderson if (a->nz) { 36406fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 36416fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 36426fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 36430b1347d2SRichard Henderson } else { 36446fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 36450b1347d2SRichard Henderson } 364630878590SRichard Henderson save_gpr(ctx, a->t, dest); 36470b1347d2SRichard Henderson 36480b1347d2SRichard Henderson /* Install the new nullification. */ 36490b1347d2SRichard Henderson cond_free(&ctx->null_cond); 365030878590SRichard Henderson if (a->c) { 365172ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36520b1347d2SRichard Henderson } 365331234768SRichard Henderson return nullify_end(ctx); 36540b1347d2SRichard Henderson } 36550b1347d2SRichard Henderson 365672ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 36570b1347d2SRichard Henderson { 365830878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 365972ae4f2bSRichard Henderson unsigned len, width; 36606fd0c7bcSRichard Henderson TCGv_i64 dest, val; 36610b1347d2SRichard Henderson 366272ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 366372ae4f2bSRichard Henderson return false; 366472ae4f2bSRichard Henderson } 366530878590SRichard Henderson if (a->c) { 36660b1347d2SRichard Henderson nullify_over(ctx); 36670b1347d2SRichard Henderson } 366872ae4f2bSRichard Henderson 366972ae4f2bSRichard Henderson len = a->len; 367072ae4f2bSRichard Henderson width = a->d ? 64 : 32; 367172ae4f2bSRichard Henderson if (a->cpos + len > width) { 367272ae4f2bSRichard Henderson len = width - a->cpos; 36730b1347d2SRichard Henderson } 36740b1347d2SRichard Henderson 367530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 367630878590SRichard Henderson val = load_gpr(ctx, a->r); 36770b1347d2SRichard Henderson if (rs == 0) { 36786fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 36790b1347d2SRichard Henderson } else { 36806fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 36810b1347d2SRichard Henderson } 368230878590SRichard Henderson save_gpr(ctx, a->t, dest); 36830b1347d2SRichard Henderson 36840b1347d2SRichard Henderson /* Install the new nullification. */ 36850b1347d2SRichard Henderson cond_free(&ctx->null_cond); 368630878590SRichard Henderson if (a->c) { 368772ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36880b1347d2SRichard Henderson } 368931234768SRichard Henderson return nullify_end(ctx); 36900b1347d2SRichard Henderson } 36910b1347d2SRichard Henderson 369272ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 36936fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 36940b1347d2SRichard Henderson { 36950b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 369672ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 36976fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3698c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 36990b1347d2SRichard Henderson 37000b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3701aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3702aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37030b1347d2SRichard Henderson 37040b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 37056fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 37066fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 37070b1347d2SRichard Henderson 3708aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 37096fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 37106fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 37110b1347d2SRichard Henderson if (rs) { 37126fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 37136fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 37146fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 37156fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 37160b1347d2SRichard Henderson } else { 37176fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 37180b1347d2SRichard Henderson } 37190b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 37200b1347d2SRichard Henderson 37210b1347d2SRichard Henderson /* Install the new nullification. */ 37220b1347d2SRichard Henderson cond_free(&ctx->null_cond); 37230b1347d2SRichard Henderson if (c) { 372472ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 37250b1347d2SRichard Henderson } 372631234768SRichard Henderson return nullify_end(ctx); 37270b1347d2SRichard Henderson } 37280b1347d2SRichard Henderson 372972ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 373030878590SRichard Henderson { 373172ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 373272ae4f2bSRichard Henderson return false; 373372ae4f2bSRichard Henderson } 3734a6deecceSSven Schnelle if (a->c) { 3735a6deecceSSven Schnelle nullify_over(ctx); 3736a6deecceSSven Schnelle } 373772ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 373872ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 373930878590SRichard Henderson } 374030878590SRichard Henderson 374172ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 374230878590SRichard Henderson { 374372ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 374472ae4f2bSRichard Henderson return false; 374572ae4f2bSRichard Henderson } 3746a6deecceSSven Schnelle if (a->c) { 3747a6deecceSSven Schnelle nullify_over(ctx); 3748a6deecceSSven Schnelle } 374972ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 37506fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 375130878590SRichard Henderson } 37520b1347d2SRichard Henderson 37538340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 375498cd9ca7SRichard Henderson { 37556fd0c7bcSRichard Henderson TCGv_i64 tmp; 375698cd9ca7SRichard Henderson 3757c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 375898cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 375998cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 376098cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 376198cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 376298cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 376398cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 376498cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 376598cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 37668340f534SRichard Henderson if (a->b == 0) { 37678340f534SRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 376898cd9ca7SRichard Henderson } 3769c301f34eSRichard Henderson #else 3770c301f34eSRichard Henderson nullify_over(ctx); 3771660eefe1SRichard Henderson #endif 3772660eefe1SRichard Henderson 3773aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37746fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp); 3775660eefe1SRichard Henderson tmp = do_ibranch_priv(ctx, tmp); 3776c301f34eSRichard Henderson 3777c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 37788340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3779c301f34eSRichard Henderson #else 3780c301f34eSRichard Henderson TCGv_i64 new_spc = tcg_temp_new_i64(); 3781c301f34eSRichard Henderson 37828340f534SRichard Henderson load_spr(ctx, new_spc, a->sp); 37838340f534SRichard Henderson if (a->l) { 3784741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); 3785c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); 3786c301f34eSRichard Henderson } 37878340f534SRichard Henderson if (a->n && use_nullify_skip(ctx)) { 3788a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 37896fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 3790a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3791c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, new_spc); 3792c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); 3793c301f34eSRichard Henderson } else { 3794741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3795c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3796c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3797c301f34eSRichard Henderson } 3798a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3799c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, new_spc); 38008340f534SRichard Henderson nullify_set(ctx, a->n); 3801c301f34eSRichard Henderson } 3802c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 380331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 380431234768SRichard Henderson return nullify_end(ctx); 3805c301f34eSRichard Henderson #endif 380698cd9ca7SRichard Henderson } 380798cd9ca7SRichard Henderson 38088340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 380998cd9ca7SRichard Henderson { 38108340f534SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n); 381198cd9ca7SRichard Henderson } 381298cd9ca7SRichard Henderson 38138340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 381443e05652SRichard Henderson { 3815c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, a->disp); 381643e05652SRichard Henderson 38176e5f5300SSven Schnelle nullify_over(ctx); 38186e5f5300SSven Schnelle 381943e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 382043e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 382143e05652SRichard Henderson * expensive to track. Real hardware will trap for 382243e05652SRichard Henderson * b gateway 382343e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 382443e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 382543e05652SRichard Henderson * diagnose the security hole 382643e05652SRichard Henderson * b gateway 382743e05652SRichard Henderson * b evil 382843e05652SRichard Henderson * in which instructions at evil would run with increased privs. 382943e05652SRichard Henderson */ 383043e05652SRichard Henderson if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) { 383143e05652SRichard Henderson return gen_illegal(ctx); 383243e05652SRichard Henderson } 383343e05652SRichard Henderson 383443e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 383543e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 383694956d7bSPhilippe Mathieu-Daudé int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next); 383743e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 383843e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 383943e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 384043e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 384143e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 384243e05652SRichard Henderson if (type < 0) { 384331234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 384431234768SRichard Henderson return true; 384543e05652SRichard Henderson } 384643e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 384743e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 384843e05652SRichard Henderson dest = deposit32(dest, 0, 2, type - 4); 384943e05652SRichard Henderson } 385043e05652SRichard Henderson } else { 385143e05652SRichard Henderson dest &= -4; /* priv = 0 */ 385243e05652SRichard Henderson } 385343e05652SRichard Henderson #endif 385443e05652SRichard Henderson 38556e5f5300SSven Schnelle if (a->l) { 38566fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 38576e5f5300SSven Schnelle if (ctx->privilege < 3) { 38586fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 38596e5f5300SSven Schnelle } 38606fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 38616e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 38626e5f5300SSven Schnelle } 38636e5f5300SSven Schnelle 38646e5f5300SSven Schnelle return do_dbranch(ctx, dest, 0, a->n); 386543e05652SRichard Henderson } 386643e05652SRichard Henderson 38678340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 386898cd9ca7SRichard Henderson { 3869b35aec85SRichard Henderson if (a->x) { 3870aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 38716fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3); 38726fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8); 3873660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 38748340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3875b35aec85SRichard Henderson } else { 3876b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 3877b35aec85SRichard Henderson return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n); 3878b35aec85SRichard Henderson } 387998cd9ca7SRichard Henderson } 388098cd9ca7SRichard Henderson 38818340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 388298cd9ca7SRichard Henderson { 38836fd0c7bcSRichard Henderson TCGv_i64 dest; 388498cd9ca7SRichard Henderson 38858340f534SRichard Henderson if (a->x == 0) { 38868340f534SRichard Henderson dest = load_gpr(ctx, a->b); 388798cd9ca7SRichard Henderson } else { 3888aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 38896fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 38906fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 389198cd9ca7SRichard Henderson } 3892660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 38938340f534SRichard Henderson return do_ibranch(ctx, dest, 0, a->n); 389498cd9ca7SRichard Henderson } 389598cd9ca7SRichard Henderson 38968340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 389798cd9ca7SRichard Henderson { 38986fd0c7bcSRichard Henderson TCGv_i64 dest; 389998cd9ca7SRichard Henderson 3900c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 39018340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 39028340f534SRichard Henderson return do_ibranch(ctx, dest, a->l, a->n); 3903c301f34eSRichard Henderson #else 3904c301f34eSRichard Henderson nullify_over(ctx); 39058340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3906c301f34eSRichard Henderson 3907741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3908c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3909c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3910c301f34eSRichard Henderson } 3911741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest); 3912c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); 39138340f534SRichard Henderson if (a->l) { 3914741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var); 3915c301f34eSRichard Henderson } 39168340f534SRichard Henderson nullify_set(ctx, a->n); 3917c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 391831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 391931234768SRichard Henderson return nullify_end(ctx); 3920c301f34eSRichard Henderson #endif 392198cd9ca7SRichard Henderson } 392298cd9ca7SRichard Henderson 3923a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 3924a8966ba7SRichard Henderson { 3925a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 3926a8966ba7SRichard Henderson return ctx->is_pa20; 3927a8966ba7SRichard Henderson } 3928a8966ba7SRichard Henderson 39291ca74648SRichard Henderson /* 39301ca74648SRichard Henderson * Float class 0 39311ca74648SRichard Henderson */ 3932ebe9383cSRichard Henderson 39331ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3934ebe9383cSRichard Henderson { 3935ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3936ebe9383cSRichard Henderson } 3937ebe9383cSRichard Henderson 393859f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 393959f8c04bSHelge Deller { 3940a300dad3SRichard Henderson uint64_t ret; 3941a300dad3SRichard Henderson 3942c53e401eSRichard Henderson if (ctx->is_pa20) { 3943a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 3944a300dad3SRichard Henderson } else { 3945a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 3946a300dad3SRichard Henderson } 3947a300dad3SRichard Henderson 394859f8c04bSHelge Deller nullify_over(ctx); 3949a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 395059f8c04bSHelge Deller return nullify_end(ctx); 395159f8c04bSHelge Deller } 395259f8c04bSHelge Deller 39531ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 39541ca74648SRichard Henderson { 39551ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 39561ca74648SRichard Henderson } 39571ca74648SRichard Henderson 3958ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3959ebe9383cSRichard Henderson { 3960ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 3961ebe9383cSRichard Henderson } 3962ebe9383cSRichard Henderson 39631ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 39641ca74648SRichard Henderson { 39651ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 39661ca74648SRichard Henderson } 39671ca74648SRichard Henderson 39681ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3969ebe9383cSRichard Henderson { 3970ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 3971ebe9383cSRichard Henderson } 3972ebe9383cSRichard Henderson 39731ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 39741ca74648SRichard Henderson { 39751ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 39761ca74648SRichard Henderson } 39771ca74648SRichard Henderson 3978ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3979ebe9383cSRichard Henderson { 3980ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 3981ebe9383cSRichard Henderson } 3982ebe9383cSRichard Henderson 39831ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 39841ca74648SRichard Henderson { 39851ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 39861ca74648SRichard Henderson } 39871ca74648SRichard Henderson 39881ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 39891ca74648SRichard Henderson { 39901ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 39911ca74648SRichard Henderson } 39921ca74648SRichard Henderson 39931ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 39941ca74648SRichard Henderson { 39951ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 39961ca74648SRichard Henderson } 39971ca74648SRichard Henderson 39981ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 39991ca74648SRichard Henderson { 40001ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 40011ca74648SRichard Henderson } 40021ca74648SRichard Henderson 40031ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 40041ca74648SRichard Henderson { 40051ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 40061ca74648SRichard Henderson } 40071ca74648SRichard Henderson 40081ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4009ebe9383cSRichard Henderson { 4010ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 4011ebe9383cSRichard Henderson } 4012ebe9383cSRichard Henderson 40131ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 40141ca74648SRichard Henderson { 40151ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 40161ca74648SRichard Henderson } 40171ca74648SRichard Henderson 4018ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4019ebe9383cSRichard Henderson { 4020ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 4021ebe9383cSRichard Henderson } 4022ebe9383cSRichard Henderson 40231ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 40241ca74648SRichard Henderson { 40251ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 40261ca74648SRichard Henderson } 40271ca74648SRichard Henderson 40281ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4029ebe9383cSRichard Henderson { 4030ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 4031ebe9383cSRichard Henderson } 4032ebe9383cSRichard Henderson 40331ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 40341ca74648SRichard Henderson { 40351ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 40361ca74648SRichard Henderson } 40371ca74648SRichard Henderson 4038ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4039ebe9383cSRichard Henderson { 4040ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4041ebe9383cSRichard Henderson } 4042ebe9383cSRichard Henderson 40431ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 40441ca74648SRichard Henderson { 40451ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 40461ca74648SRichard Henderson } 40471ca74648SRichard Henderson 40481ca74648SRichard Henderson /* 40491ca74648SRichard Henderson * Float class 1 40501ca74648SRichard Henderson */ 40511ca74648SRichard Henderson 40521ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 40531ca74648SRichard Henderson { 40541ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 40551ca74648SRichard Henderson } 40561ca74648SRichard Henderson 40571ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 40581ca74648SRichard Henderson { 40591ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 40601ca74648SRichard Henderson } 40611ca74648SRichard Henderson 40621ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 40631ca74648SRichard Henderson { 40641ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 40651ca74648SRichard Henderson } 40661ca74648SRichard Henderson 40671ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 40681ca74648SRichard Henderson { 40691ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 40701ca74648SRichard Henderson } 40711ca74648SRichard Henderson 40721ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 40731ca74648SRichard Henderson { 40741ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 40751ca74648SRichard Henderson } 40761ca74648SRichard Henderson 40771ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 40781ca74648SRichard Henderson { 40791ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 40801ca74648SRichard Henderson } 40811ca74648SRichard Henderson 40821ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 40831ca74648SRichard Henderson { 40841ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 40851ca74648SRichard Henderson } 40861ca74648SRichard Henderson 40871ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 40881ca74648SRichard Henderson { 40891ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 40901ca74648SRichard Henderson } 40911ca74648SRichard Henderson 40921ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 40931ca74648SRichard Henderson { 40941ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 40951ca74648SRichard Henderson } 40961ca74648SRichard Henderson 40971ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 40981ca74648SRichard Henderson { 40991ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 41001ca74648SRichard Henderson } 41011ca74648SRichard Henderson 41021ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 41031ca74648SRichard Henderson { 41041ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 41051ca74648SRichard Henderson } 41061ca74648SRichard Henderson 41071ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 41081ca74648SRichard Henderson { 41091ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 41101ca74648SRichard Henderson } 41111ca74648SRichard Henderson 41121ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 41131ca74648SRichard Henderson { 41141ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 41151ca74648SRichard Henderson } 41161ca74648SRichard Henderson 41171ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 41181ca74648SRichard Henderson { 41191ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 41201ca74648SRichard Henderson } 41211ca74648SRichard Henderson 41221ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 41231ca74648SRichard Henderson { 41241ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 41251ca74648SRichard Henderson } 41261ca74648SRichard Henderson 41271ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 41281ca74648SRichard Henderson { 41291ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 41301ca74648SRichard Henderson } 41311ca74648SRichard Henderson 41321ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 41331ca74648SRichard Henderson { 41341ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 41351ca74648SRichard Henderson } 41361ca74648SRichard Henderson 41371ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 41381ca74648SRichard Henderson { 41391ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 41401ca74648SRichard Henderson } 41411ca74648SRichard Henderson 41421ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 41431ca74648SRichard Henderson { 41441ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 41451ca74648SRichard Henderson } 41461ca74648SRichard Henderson 41471ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 41481ca74648SRichard Henderson { 41491ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 41501ca74648SRichard Henderson } 41511ca74648SRichard Henderson 41521ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 41531ca74648SRichard Henderson { 41541ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 41551ca74648SRichard Henderson } 41561ca74648SRichard Henderson 41571ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 41581ca74648SRichard Henderson { 41591ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 41601ca74648SRichard Henderson } 41611ca74648SRichard Henderson 41621ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 41631ca74648SRichard Henderson { 41641ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 41651ca74648SRichard Henderson } 41661ca74648SRichard Henderson 41671ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 41681ca74648SRichard Henderson { 41691ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 41701ca74648SRichard Henderson } 41711ca74648SRichard Henderson 41721ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 41731ca74648SRichard Henderson { 41741ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 41751ca74648SRichard Henderson } 41761ca74648SRichard Henderson 41771ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 41781ca74648SRichard Henderson { 41791ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 41801ca74648SRichard Henderson } 41811ca74648SRichard Henderson 41821ca74648SRichard Henderson /* 41831ca74648SRichard Henderson * Float class 2 41841ca74648SRichard Henderson */ 41851ca74648SRichard Henderson 41861ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4187ebe9383cSRichard Henderson { 4188ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4189ebe9383cSRichard Henderson 4190ebe9383cSRichard Henderson nullify_over(ctx); 4191ebe9383cSRichard Henderson 41921ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 41931ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 419429dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 419529dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4196ebe9383cSRichard Henderson 4197ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4198ebe9383cSRichard Henderson 41991ca74648SRichard Henderson return nullify_end(ctx); 4200ebe9383cSRichard Henderson } 4201ebe9383cSRichard Henderson 42021ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4203ebe9383cSRichard Henderson { 4204ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4205ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4206ebe9383cSRichard Henderson 4207ebe9383cSRichard Henderson nullify_over(ctx); 4208ebe9383cSRichard Henderson 42091ca74648SRichard Henderson ta = load_frd0(a->r1); 42101ca74648SRichard Henderson tb = load_frd0(a->r2); 421129dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 421229dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4213ebe9383cSRichard Henderson 4214ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4215ebe9383cSRichard Henderson 421631234768SRichard Henderson return nullify_end(ctx); 4217ebe9383cSRichard Henderson } 4218ebe9383cSRichard Henderson 42191ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4220ebe9383cSRichard Henderson { 42216fd0c7bcSRichard Henderson TCGv_i64 t; 4222ebe9383cSRichard Henderson 4223ebe9383cSRichard Henderson nullify_over(ctx); 4224ebe9383cSRichard Henderson 4225aac0f603SRichard Henderson t = tcg_temp_new_i64(); 42266fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4227ebe9383cSRichard Henderson 42281ca74648SRichard Henderson if (a->y == 1) { 4229ebe9383cSRichard Henderson int mask; 4230ebe9383cSRichard Henderson bool inv = false; 4231ebe9383cSRichard Henderson 42321ca74648SRichard Henderson switch (a->c) { 4233ebe9383cSRichard Henderson case 0: /* simple */ 42346fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 4235ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4236ebe9383cSRichard Henderson goto done; 4237ebe9383cSRichard Henderson case 2: /* rej */ 4238ebe9383cSRichard Henderson inv = true; 4239ebe9383cSRichard Henderson /* fallthru */ 4240ebe9383cSRichard Henderson case 1: /* acc */ 4241ebe9383cSRichard Henderson mask = 0x43ff800; 4242ebe9383cSRichard Henderson break; 4243ebe9383cSRichard Henderson case 6: /* rej8 */ 4244ebe9383cSRichard Henderson inv = true; 4245ebe9383cSRichard Henderson /* fallthru */ 4246ebe9383cSRichard Henderson case 5: /* acc8 */ 4247ebe9383cSRichard Henderson mask = 0x43f8000; 4248ebe9383cSRichard Henderson break; 4249ebe9383cSRichard Henderson case 9: /* acc6 */ 4250ebe9383cSRichard Henderson mask = 0x43e0000; 4251ebe9383cSRichard Henderson break; 4252ebe9383cSRichard Henderson case 13: /* acc4 */ 4253ebe9383cSRichard Henderson mask = 0x4380000; 4254ebe9383cSRichard Henderson break; 4255ebe9383cSRichard Henderson case 17: /* acc2 */ 4256ebe9383cSRichard Henderson mask = 0x4200000; 4257ebe9383cSRichard Henderson break; 4258ebe9383cSRichard Henderson default: 42591ca74648SRichard Henderson gen_illegal(ctx); 42601ca74648SRichard Henderson return true; 4261ebe9383cSRichard Henderson } 4262ebe9383cSRichard Henderson if (inv) { 42636fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 42646fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 4265ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 4266ebe9383cSRichard Henderson } else { 42676fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 4268ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 4269ebe9383cSRichard Henderson } 42701ca74648SRichard Henderson } else { 42711ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 42721ca74648SRichard Henderson 42736fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 42741ca74648SRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 42751ca74648SRichard Henderson } 42761ca74648SRichard Henderson 4277ebe9383cSRichard Henderson done: 427831234768SRichard Henderson return nullify_end(ctx); 4279ebe9383cSRichard Henderson } 4280ebe9383cSRichard Henderson 42811ca74648SRichard Henderson /* 42821ca74648SRichard Henderson * Float class 2 42831ca74648SRichard Henderson */ 42841ca74648SRichard Henderson 42851ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4286ebe9383cSRichard Henderson { 42871ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 42881ca74648SRichard Henderson } 42891ca74648SRichard Henderson 42901ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 42911ca74648SRichard Henderson { 42921ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 42931ca74648SRichard Henderson } 42941ca74648SRichard Henderson 42951ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 42961ca74648SRichard Henderson { 42971ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 42981ca74648SRichard Henderson } 42991ca74648SRichard Henderson 43001ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 43011ca74648SRichard Henderson { 43021ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 43031ca74648SRichard Henderson } 43041ca74648SRichard Henderson 43051ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 43061ca74648SRichard Henderson { 43071ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 43081ca74648SRichard Henderson } 43091ca74648SRichard Henderson 43101ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 43111ca74648SRichard Henderson { 43121ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 43131ca74648SRichard Henderson } 43141ca74648SRichard Henderson 43151ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 43161ca74648SRichard Henderson { 43171ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 43181ca74648SRichard Henderson } 43191ca74648SRichard Henderson 43201ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 43211ca74648SRichard Henderson { 43221ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 43231ca74648SRichard Henderson } 43241ca74648SRichard Henderson 43251ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 43261ca74648SRichard Henderson { 43271ca74648SRichard Henderson TCGv_i64 x, y; 4328ebe9383cSRichard Henderson 4329ebe9383cSRichard Henderson nullify_over(ctx); 4330ebe9383cSRichard Henderson 43311ca74648SRichard Henderson x = load_frw0_i64(a->r1); 43321ca74648SRichard Henderson y = load_frw0_i64(a->r2); 43331ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 43341ca74648SRichard Henderson save_frd(a->t, x); 4335ebe9383cSRichard Henderson 433631234768SRichard Henderson return nullify_end(ctx); 4337ebe9383cSRichard Henderson } 4338ebe9383cSRichard Henderson 4339ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4340ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4341ebe9383cSRichard Henderson { 4342ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4343ebe9383cSRichard Henderson } 4344ebe9383cSRichard Henderson 4345b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4346ebe9383cSRichard Henderson { 4347b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4348b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4349b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4350b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4351b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4352ebe9383cSRichard Henderson 4353ebe9383cSRichard Henderson nullify_over(ctx); 4354ebe9383cSRichard Henderson 4355ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4356ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4357ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4358ebe9383cSRichard Henderson 435931234768SRichard Henderson return nullify_end(ctx); 4360ebe9383cSRichard Henderson } 4361ebe9383cSRichard Henderson 4362b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4363b1e2af57SRichard Henderson { 4364b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4365b1e2af57SRichard Henderson } 4366b1e2af57SRichard Henderson 4367b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4368b1e2af57SRichard Henderson { 4369b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4370b1e2af57SRichard Henderson } 4371b1e2af57SRichard Henderson 4372b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4373b1e2af57SRichard Henderson { 4374b1e2af57SRichard Henderson nullify_over(ctx); 4375b1e2af57SRichard Henderson 4376b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4377b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4378b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4379b1e2af57SRichard Henderson 4380b1e2af57SRichard Henderson return nullify_end(ctx); 4381b1e2af57SRichard Henderson } 4382b1e2af57SRichard Henderson 4383b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4384b1e2af57SRichard Henderson { 4385b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4386b1e2af57SRichard Henderson } 4387b1e2af57SRichard Henderson 4388b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4389b1e2af57SRichard Henderson { 4390b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4391b1e2af57SRichard Henderson } 4392b1e2af57SRichard Henderson 4393c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4394ebe9383cSRichard Henderson { 4395c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4396ebe9383cSRichard Henderson 4397ebe9383cSRichard Henderson nullify_over(ctx); 4398c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4399c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4400c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4401ebe9383cSRichard Henderson 4402c3bad4f8SRichard Henderson if (a->neg) { 4403ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4404ebe9383cSRichard Henderson } else { 4405ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4406ebe9383cSRichard Henderson } 4407ebe9383cSRichard Henderson 4408c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 440931234768SRichard Henderson return nullify_end(ctx); 4410ebe9383cSRichard Henderson } 4411ebe9383cSRichard Henderson 4412c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4413ebe9383cSRichard Henderson { 4414c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4415ebe9383cSRichard Henderson 4416ebe9383cSRichard Henderson nullify_over(ctx); 4417c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4418c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4419c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4420ebe9383cSRichard Henderson 4421c3bad4f8SRichard Henderson if (a->neg) { 4422ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4423ebe9383cSRichard Henderson } else { 4424ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4425ebe9383cSRichard Henderson } 4426ebe9383cSRichard Henderson 4427c3bad4f8SRichard Henderson save_frd(a->t, x); 442831234768SRichard Henderson return nullify_end(ctx); 4429ebe9383cSRichard Henderson } 4430ebe9383cSRichard Henderson 443115da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a) 443215da177bSSven Schnelle { 4433cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4434cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4435cf6b28d4SHelge Deller if (a->i == 0x100) { 4436cf6b28d4SHelge Deller /* emulate PDC BTLB, called by SeaBIOS-hppa */ 4437ad75a51eSRichard Henderson nullify_over(ctx); 4438ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4439cf6b28d4SHelge Deller return nullify_end(ctx); 444015da177bSSven Schnelle } 4441dbca0835SHelge Deller if (a->i == 0x101) { 4442dbca0835SHelge Deller /* print char in %r26 to first serial console, used by SeaBIOS-hppa */ 4443dbca0835SHelge Deller nullify_over(ctx); 4444dbca0835SHelge Deller gen_helper_diag_console_output(tcg_env); 4445dbca0835SHelge Deller return nullify_end(ctx); 4446dbca0835SHelge Deller } 4447ad75a51eSRichard Henderson #endif 4448ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4449ad75a51eSRichard Henderson return true; 4450ad75a51eSRichard Henderson } 445115da177bSSven Schnelle 4452b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 445361766fe9SRichard Henderson { 445451b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4455f764718dSRichard Henderson int bound; 445661766fe9SRichard Henderson 445751b061fbSRichard Henderson ctx->cs = cs; 4458494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4459bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 44603d68ee7bSRichard Henderson 44613d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4462c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 44633d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 4464c01e5dfbSHelge Deller ctx->iaoq_f = ctx->base.pc_first | ctx->privilege; 4465c01e5dfbSHelge Deller ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege; 4466217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4467c301f34eSRichard Henderson #else 4468494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4469bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4470bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4471451d993dSRichard Henderson : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX); 44723d68ee7bSRichard Henderson 4473c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4474c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4475c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4476c301f34eSRichard Henderson int32_t diff = cs_base; 4477c301f34eSRichard Henderson 4478c301f34eSRichard Henderson ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4479c301f34eSRichard Henderson ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); 4480c301f34eSRichard Henderson #endif 448151b061fbSRichard Henderson ctx->iaoq_n = -1; 4482f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 448361766fe9SRichard Henderson 4484a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4485a4db4a78SRichard Henderson 44863d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 44873d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4488b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 448961766fe9SRichard Henderson } 449061766fe9SRichard Henderson 449151b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 449251b061fbSRichard Henderson { 449351b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 449461766fe9SRichard Henderson 44953d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 449651b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 449751b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4498494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 449951b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 450051b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4501129e9cc3SRichard Henderson } 450251b061fbSRichard Henderson ctx->null_lab = NULL; 450361766fe9SRichard Henderson } 450461766fe9SRichard Henderson 450551b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 450651b061fbSRichard Henderson { 450751b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 450851b061fbSRichard Henderson 4509f5b5c857SRichard Henderson tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0); 4510f5b5c857SRichard Henderson ctx->insn_start = tcg_last_op(); 451151b061fbSRichard Henderson } 451251b061fbSRichard Henderson 451351b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 451451b061fbSRichard Henderson { 451551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4516b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 451751b061fbSRichard Henderson DisasJumpType ret; 451851b061fbSRichard Henderson 451951b061fbSRichard Henderson /* Execute one insn. */ 4520ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4521c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 452231234768SRichard Henderson do_page_zero(ctx); 452331234768SRichard Henderson ret = ctx->base.is_jmp; 4524869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4525ba1d0b44SRichard Henderson } else 4526ba1d0b44SRichard Henderson #endif 4527ba1d0b44SRichard Henderson { 452861766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 452961766fe9SRichard Henderson the page permissions for execute. */ 45304e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 453161766fe9SRichard Henderson 453261766fe9SRichard Henderson /* Set up the IA queue for the next insn. 453361766fe9SRichard Henderson This will be overwritten by a branch. */ 453451b061fbSRichard Henderson if (ctx->iaoq_b == -1) { 453551b061fbSRichard Henderson ctx->iaoq_n = -1; 4536aac0f603SRichard Henderson ctx->iaoq_n_var = tcg_temp_new_i64(); 45376fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 453861766fe9SRichard Henderson } else { 453951b061fbSRichard Henderson ctx->iaoq_n = ctx->iaoq_b + 4; 4540f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 454161766fe9SRichard Henderson } 454261766fe9SRichard Henderson 454351b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 454451b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4545869051eaSRichard Henderson ret = DISAS_NEXT; 4546129e9cc3SRichard Henderson } else { 45471a19da0dSRichard Henderson ctx->insn = insn; 454831274b46SRichard Henderson if (!decode(ctx, insn)) { 454931274b46SRichard Henderson gen_illegal(ctx); 455031274b46SRichard Henderson } 455131234768SRichard Henderson ret = ctx->base.is_jmp; 455251b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4553129e9cc3SRichard Henderson } 455461766fe9SRichard Henderson } 455561766fe9SRichard Henderson 45563d68ee7bSRichard Henderson /* Advance the insn queue. Note that this check also detects 45573d68ee7bSRichard Henderson a priority change within the instruction queue. */ 455851b061fbSRichard Henderson if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 4559c301f34eSRichard Henderson if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 4560c301f34eSRichard Henderson && use_goto_tb(ctx, ctx->iaoq_b) 4561c301f34eSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4562c301f34eSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 456351b061fbSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 456451b061fbSRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 456531234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_NORETURN; 4566129e9cc3SRichard Henderson } else { 456731234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE; 456861766fe9SRichard Henderson } 4569129e9cc3SRichard Henderson } 457051b061fbSRichard Henderson ctx->iaoq_f = ctx->iaoq_b; 457151b061fbSRichard Henderson ctx->iaoq_b = ctx->iaoq_n; 4572c301f34eSRichard Henderson ctx->base.pc_next += 4; 457361766fe9SRichard Henderson 4574c5d0aec2SRichard Henderson switch (ret) { 4575c5d0aec2SRichard Henderson case DISAS_NORETURN: 4576c5d0aec2SRichard Henderson case DISAS_IAQ_N_UPDATED: 4577c5d0aec2SRichard Henderson break; 4578c5d0aec2SRichard Henderson 4579c5d0aec2SRichard Henderson case DISAS_NEXT: 4580c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE: 4581c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 458251b061fbSRichard Henderson if (ctx->iaoq_f == -1) { 4583a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b); 4584741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 4585c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY 4586c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 4587c301f34eSRichard Henderson #endif 458851b061fbSRichard Henderson nullify_save(ctx); 4589c5d0aec2SRichard Henderson ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT 4590c5d0aec2SRichard Henderson ? DISAS_EXIT 4591c5d0aec2SRichard Henderson : DISAS_IAQ_N_UPDATED); 459251b061fbSRichard Henderson } else if (ctx->iaoq_b == -1) { 4593a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var); 459461766fe9SRichard Henderson } 4595c5d0aec2SRichard Henderson break; 4596c5d0aec2SRichard Henderson 4597c5d0aec2SRichard Henderson default: 4598c5d0aec2SRichard Henderson g_assert_not_reached(); 4599c5d0aec2SRichard Henderson } 460061766fe9SRichard Henderson } 460161766fe9SRichard Henderson 460251b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 460351b061fbSRichard Henderson { 460451b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4605e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 460651b061fbSRichard Henderson 4607e1b5a5edSRichard Henderson switch (is_jmp) { 4608869051eaSRichard Henderson case DISAS_NORETURN: 460961766fe9SRichard Henderson break; 461051b061fbSRichard Henderson case DISAS_TOO_MANY: 4611869051eaSRichard Henderson case DISAS_IAQ_N_STALE: 4612e1b5a5edSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4613741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 4614741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 461551b061fbSRichard Henderson nullify_save(ctx); 461661766fe9SRichard Henderson /* FALLTHRU */ 4617869051eaSRichard Henderson case DISAS_IAQ_N_UPDATED: 46188532a14eSRichard Henderson if (is_jmp != DISAS_IAQ_N_STALE_EXIT) { 46197f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 46208532a14eSRichard Henderson break; 462161766fe9SRichard Henderson } 4622c5d0aec2SRichard Henderson /* FALLTHRU */ 4623c5d0aec2SRichard Henderson case DISAS_EXIT: 4624c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 462561766fe9SRichard Henderson break; 462661766fe9SRichard Henderson default: 462751b061fbSRichard Henderson g_assert_not_reached(); 462861766fe9SRichard Henderson } 462951b061fbSRichard Henderson } 463061766fe9SRichard Henderson 46318eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 46328eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 463351b061fbSRichard Henderson { 4634c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 463561766fe9SRichard Henderson 4636ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4637ba1d0b44SRichard Henderson switch (pc) { 46387ad439dfSRichard Henderson case 0x00: 46398eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4640ba1d0b44SRichard Henderson return; 46417ad439dfSRichard Henderson case 0xb0: 46428eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4643ba1d0b44SRichard Henderson return; 46447ad439dfSRichard Henderson case 0xe0: 46458eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4646ba1d0b44SRichard Henderson return; 46477ad439dfSRichard Henderson case 0x100: 46488eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4649ba1d0b44SRichard Henderson return; 46507ad439dfSRichard Henderson } 4651ba1d0b44SRichard Henderson #endif 4652ba1d0b44SRichard Henderson 46538eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 46548eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 465561766fe9SRichard Henderson } 465651b061fbSRichard Henderson 465751b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 465851b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 465951b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 466051b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 466151b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 466251b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 466351b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 466451b061fbSRichard Henderson }; 466551b061fbSRichard Henderson 4666597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 466732f0c394SAnton Johansson vaddr pc, void *host_pc) 466851b061fbSRichard Henderson { 466951b061fbSRichard Henderson DisasContext ctx; 4670306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 467161766fe9SRichard Henderson } 4672