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 147c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */ 148c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val) 149c65c3ee1SRichard Henderson { 150c65c3ee1SRichard Henderson return val ? val : 4; /* 0 == "*<<" */ 151c65c3ee1SRichard Henderson } 152c65c3ee1SRichard Henderson 15301afb7beSRichard Henderson 15440f9f908SRichard Henderson /* Include the auto-generated decoder. */ 155abff1abfSPaolo Bonzini #include "decode-insns.c.inc" 15640f9f908SRichard Henderson 15761766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 15861766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 159869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 16061766fe9SRichard Henderson 16161766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 16261766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 163869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 16461766fe9SRichard Henderson 165e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 166e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 167e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 168c5d0aec2SRichard Henderson #define DISAS_EXIT DISAS_TARGET_3 169e1b5a5edSRichard Henderson 17061766fe9SRichard Henderson /* global register indexes */ 1716fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32]; 17233423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 173494737b7SRichard Henderson static TCGv_i64 cpu_srH; 1746fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f; 1756fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b; 176c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 177c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 1786fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar; 1796fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n; 1806fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v; 1816fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb; 1826fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb; 18361766fe9SRichard Henderson 18461766fe9SRichard Henderson void hppa_translate_init(void) 18561766fe9SRichard Henderson { 18661766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 18761766fe9SRichard Henderson 1886fd0c7bcSRichard Henderson typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 18961766fe9SRichard Henderson static const GlobalVar vars[] = { 19035136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 19161766fe9SRichard Henderson DEF_VAR(psw_n), 19261766fe9SRichard Henderson DEF_VAR(psw_v), 19361766fe9SRichard Henderson DEF_VAR(psw_cb), 19461766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 19561766fe9SRichard Henderson DEF_VAR(iaoq_f), 19661766fe9SRichard Henderson DEF_VAR(iaoq_b), 19761766fe9SRichard Henderson }; 19861766fe9SRichard Henderson 19961766fe9SRichard Henderson #undef DEF_VAR 20061766fe9SRichard Henderson 20161766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 20261766fe9SRichard Henderson static const char gr_names[32][4] = { 20361766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 20461766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 20561766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 20661766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 20761766fe9SRichard Henderson }; 20833423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 209494737b7SRichard Henderson static const char sr_names[5][4] = { 210494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 21133423472SRichard Henderson }; 21261766fe9SRichard Henderson 21361766fe9SRichard Henderson int i; 21461766fe9SRichard Henderson 215f764718dSRichard Henderson cpu_gr[0] = NULL; 21661766fe9SRichard Henderson for (i = 1; i < 32; i++) { 217ad75a51eSRichard Henderson cpu_gr[i] = tcg_global_mem_new(tcg_env, 21861766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 21961766fe9SRichard Henderson gr_names[i]); 22061766fe9SRichard Henderson } 22133423472SRichard Henderson for (i = 0; i < 4; i++) { 222ad75a51eSRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 22333423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 22433423472SRichard Henderson sr_names[i]); 22533423472SRichard Henderson } 226ad75a51eSRichard Henderson cpu_srH = tcg_global_mem_new_i64(tcg_env, 227494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 228494737b7SRichard Henderson sr_names[4]); 22961766fe9SRichard Henderson 23061766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 23161766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 232ad75a51eSRichard Henderson *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 23361766fe9SRichard Henderson } 234c301f34eSRichard Henderson 235ad75a51eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 236c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 237c301f34eSRichard Henderson "iasq_f"); 238ad75a51eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 239c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 240c301f34eSRichard Henderson "iasq_b"); 24161766fe9SRichard Henderson } 24261766fe9SRichard Henderson 243f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg) 244f5b5c857SRichard Henderson { 245f5b5c857SRichard Henderson assert(ctx->insn_start != NULL); 246f5b5c857SRichard Henderson tcg_set_insn_start_param(ctx->insn_start, 2, breg); 247f5b5c857SRichard Henderson ctx->insn_start = NULL; 248f5b5c857SRichard Henderson } 249f5b5c857SRichard Henderson 250129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 251129e9cc3SRichard Henderson { 252f764718dSRichard Henderson return (DisasCond){ 253f764718dSRichard Henderson .c = TCG_COND_NEVER, 254f764718dSRichard Henderson .a0 = NULL, 255f764718dSRichard Henderson .a1 = NULL, 256f764718dSRichard Henderson }; 257129e9cc3SRichard Henderson } 258129e9cc3SRichard Henderson 259df0232feSRichard Henderson static DisasCond cond_make_t(void) 260df0232feSRichard Henderson { 261df0232feSRichard Henderson return (DisasCond){ 262df0232feSRichard Henderson .c = TCG_COND_ALWAYS, 263df0232feSRichard Henderson .a0 = NULL, 264df0232feSRichard Henderson .a1 = NULL, 265df0232feSRichard Henderson }; 266df0232feSRichard Henderson } 267df0232feSRichard Henderson 268129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 269129e9cc3SRichard Henderson { 270f764718dSRichard Henderson return (DisasCond){ 271f764718dSRichard Henderson .c = TCG_COND_NE, 272f764718dSRichard Henderson .a0 = cpu_psw_n, 2736fd0c7bcSRichard Henderson .a1 = tcg_constant_i64(0) 274f764718dSRichard Henderson }; 275129e9cc3SRichard Henderson } 276129e9cc3SRichard Henderson 2776fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 278b47a4a02SSven Schnelle { 279b47a4a02SSven Schnelle assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 2804fe9533aSRichard Henderson return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 2814fe9533aSRichard Henderson } 2824fe9533aSRichard Henderson 2836fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0) 2844fe9533aSRichard Henderson { 2856fd0c7bcSRichard Henderson return cond_make_tmp(c, a0, tcg_constant_i64(0)); 286b47a4a02SSven Schnelle } 287b47a4a02SSven Schnelle 2886fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0) 289129e9cc3SRichard Henderson { 290aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2916fd0c7bcSRichard Henderson tcg_gen_mov_i64(tmp, a0); 292b47a4a02SSven Schnelle return cond_make_0_tmp(c, tmp); 293129e9cc3SRichard Henderson } 294129e9cc3SRichard Henderson 2956fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 296129e9cc3SRichard Henderson { 297aac0f603SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 298aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 299129e9cc3SRichard Henderson 3006fd0c7bcSRichard Henderson tcg_gen_mov_i64(t0, a0); 3016fd0c7bcSRichard Henderson tcg_gen_mov_i64(t1, a1); 3024fe9533aSRichard Henderson return cond_make_tmp(c, t0, t1); 303129e9cc3SRichard Henderson } 304129e9cc3SRichard Henderson 305129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 306129e9cc3SRichard Henderson { 307129e9cc3SRichard Henderson switch (cond->c) { 308129e9cc3SRichard Henderson default: 309f764718dSRichard Henderson cond->a0 = NULL; 310f764718dSRichard Henderson cond->a1 = NULL; 311129e9cc3SRichard Henderson /* fallthru */ 312129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 313129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 314129e9cc3SRichard Henderson break; 315129e9cc3SRichard Henderson case TCG_COND_NEVER: 316129e9cc3SRichard Henderson break; 317129e9cc3SRichard Henderson } 318129e9cc3SRichard Henderson } 319129e9cc3SRichard Henderson 3206fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 32161766fe9SRichard Henderson { 32261766fe9SRichard Henderson if (reg == 0) { 323bc3da3cfSRichard Henderson return ctx->zero; 32461766fe9SRichard Henderson } else { 32561766fe9SRichard Henderson return cpu_gr[reg]; 32661766fe9SRichard Henderson } 32761766fe9SRichard Henderson } 32861766fe9SRichard Henderson 3296fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 33061766fe9SRichard Henderson { 331129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 332aac0f603SRichard Henderson return tcg_temp_new_i64(); 33361766fe9SRichard Henderson } else { 33461766fe9SRichard Henderson return cpu_gr[reg]; 33561766fe9SRichard Henderson } 33661766fe9SRichard Henderson } 33761766fe9SRichard Henderson 3386fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 339129e9cc3SRichard Henderson { 340129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 3416fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 342129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 343129e9cc3SRichard Henderson } else { 3446fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 345129e9cc3SRichard Henderson } 346129e9cc3SRichard Henderson } 347129e9cc3SRichard Henderson 3486fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 349129e9cc3SRichard Henderson { 350129e9cc3SRichard Henderson if (reg != 0) { 351129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 352129e9cc3SRichard Henderson } 353129e9cc3SRichard Henderson } 354129e9cc3SRichard Henderson 355e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 35696d6407fSRichard Henderson # define HI_OFS 0 35796d6407fSRichard Henderson # define LO_OFS 4 35896d6407fSRichard Henderson #else 35996d6407fSRichard Henderson # define HI_OFS 4 36096d6407fSRichard Henderson # define LO_OFS 0 36196d6407fSRichard Henderson #endif 36296d6407fSRichard Henderson 36396d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 36496d6407fSRichard Henderson { 36596d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 366ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 36796d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 36896d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 36996d6407fSRichard Henderson return ret; 37096d6407fSRichard Henderson } 37196d6407fSRichard Henderson 372ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 373ebe9383cSRichard Henderson { 374ebe9383cSRichard Henderson if (rt == 0) { 3750992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 3760992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 3770992a930SRichard Henderson return ret; 378ebe9383cSRichard Henderson } else { 379ebe9383cSRichard Henderson return load_frw_i32(rt); 380ebe9383cSRichard Henderson } 381ebe9383cSRichard Henderson } 382ebe9383cSRichard Henderson 383ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 384ebe9383cSRichard Henderson { 385ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 3860992a930SRichard Henderson if (rt == 0) { 3870992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 3880992a930SRichard Henderson } else { 389ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 390ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 391ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 392ebe9383cSRichard Henderson } 3930992a930SRichard Henderson return ret; 394ebe9383cSRichard Henderson } 395ebe9383cSRichard Henderson 39696d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 39796d6407fSRichard Henderson { 398ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 39996d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 40096d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 40196d6407fSRichard Henderson } 40296d6407fSRichard Henderson 40396d6407fSRichard Henderson #undef HI_OFS 40496d6407fSRichard Henderson #undef LO_OFS 40596d6407fSRichard Henderson 40696d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 40796d6407fSRichard Henderson { 40896d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 409ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 41096d6407fSRichard Henderson return ret; 41196d6407fSRichard Henderson } 41296d6407fSRichard Henderson 413ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 414ebe9383cSRichard Henderson { 415ebe9383cSRichard Henderson if (rt == 0) { 4160992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4170992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4180992a930SRichard Henderson return ret; 419ebe9383cSRichard Henderson } else { 420ebe9383cSRichard Henderson return load_frd(rt); 421ebe9383cSRichard Henderson } 422ebe9383cSRichard Henderson } 423ebe9383cSRichard Henderson 42496d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 42596d6407fSRichard Henderson { 426ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 42796d6407fSRichard Henderson } 42896d6407fSRichard Henderson 42933423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 43033423472SRichard Henderson { 43133423472SRichard Henderson #ifdef CONFIG_USER_ONLY 43233423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 43333423472SRichard Henderson #else 43433423472SRichard Henderson if (reg < 4) { 43533423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 436494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 437494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 43833423472SRichard Henderson } else { 439ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 44033423472SRichard Henderson } 44133423472SRichard Henderson #endif 44233423472SRichard Henderson } 44333423472SRichard Henderson 444129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 445129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 446129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 447129e9cc3SRichard Henderson { 448129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 449129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 450129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 451129e9cc3SRichard Henderson 452129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 453129e9cc3SRichard Henderson 454129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 4556e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 456aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 4576fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 458129e9cc3SRichard Henderson } 459129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 460129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 461129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 462129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 463129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 4646fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 465129e9cc3SRichard Henderson } 466129e9cc3SRichard Henderson 4676fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 468129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 469129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 470129e9cc3SRichard Henderson } 471129e9cc3SRichard Henderson } 472129e9cc3SRichard Henderson 473129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 474129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 475129e9cc3SRichard Henderson { 476129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 477129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 4786fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 479129e9cc3SRichard Henderson } 480129e9cc3SRichard Henderson return; 481129e9cc3SRichard Henderson } 4826e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 4836fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 484129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 485129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 486129e9cc3SRichard Henderson } 487129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 488129e9cc3SRichard Henderson } 489129e9cc3SRichard Henderson 490129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 491129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 492129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 493129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 494129e9cc3SRichard Henderson { 495129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 4966fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 497129e9cc3SRichard Henderson } 498129e9cc3SRichard Henderson } 499129e9cc3SRichard Henderson 500129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 50140f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 50240f9f908SRichard Henderson it may be tail-called from a translate function. */ 50331234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 504129e9cc3SRichard Henderson { 505129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 50631234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 507129e9cc3SRichard Henderson 508f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 509f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 510f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 511f49b3537SRichard Henderson 512129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 513129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 514129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 515129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 51631234768SRichard Henderson return true; 517129e9cc3SRichard Henderson } 518129e9cc3SRichard Henderson ctx->null_lab = NULL; 519129e9cc3SRichard Henderson 520129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 521129e9cc3SRichard Henderson /* The next instruction will be unconditional, 522129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 523129e9cc3SRichard Henderson gen_set_label(null_lab); 524129e9cc3SRichard Henderson } else { 525129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 526129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 527129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 528129e9cc3SRichard Henderson label we have the proper value in place. */ 529129e9cc3SRichard Henderson nullify_save(ctx); 530129e9cc3SRichard Henderson gen_set_label(null_lab); 531129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 532129e9cc3SRichard Henderson } 533869051eaSRichard Henderson if (status == DISAS_NORETURN) { 53431234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 535129e9cc3SRichard Henderson } 53631234768SRichard Henderson return true; 537129e9cc3SRichard Henderson } 538129e9cc3SRichard Henderson 539c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx) 540698240d1SRichard Henderson { 541698240d1SRichard Henderson return (ctx->tb_flags & PSW_W 542698240d1SRichard Henderson ? MAKE_64BIT_MASK(0, 62) 543698240d1SRichard Henderson : MAKE_64BIT_MASK(0, 32)); 544698240d1SRichard Henderson } 545698240d1SRichard Henderson 5466fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 5476fd0c7bcSRichard Henderson uint64_t ival, TCGv_i64 vval) 54861766fe9SRichard Henderson { 549c53e401eSRichard Henderson uint64_t mask = gva_offset_mask(ctx); 550f13bf343SRichard Henderson 551f13bf343SRichard Henderson if (ival != -1) { 5526fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, ival & mask); 553f13bf343SRichard Henderson return; 554f13bf343SRichard Henderson } 555f13bf343SRichard Henderson tcg_debug_assert(vval != NULL); 556f13bf343SRichard Henderson 557f13bf343SRichard Henderson /* 558f13bf343SRichard Henderson * We know that the IAOQ is already properly masked. 559f13bf343SRichard Henderson * This optimization is primarily for "iaoq_f = iaoq_b". 560f13bf343SRichard Henderson */ 561f13bf343SRichard Henderson if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) { 5626fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, vval); 56361766fe9SRichard Henderson } else { 5646fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, vval, mask); 56561766fe9SRichard Henderson } 56661766fe9SRichard Henderson } 56761766fe9SRichard Henderson 568c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp) 56961766fe9SRichard Henderson { 57061766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 57161766fe9SRichard Henderson } 57261766fe9SRichard Henderson 57361766fe9SRichard Henderson static void gen_excp_1(int exception) 57461766fe9SRichard Henderson { 575ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 57661766fe9SRichard Henderson } 57761766fe9SRichard Henderson 57831234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 57961766fe9SRichard Henderson { 580741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 581741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 582129e9cc3SRichard Henderson nullify_save(ctx); 58361766fe9SRichard Henderson gen_excp_1(exception); 58431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 58561766fe9SRichard Henderson } 58661766fe9SRichard Henderson 58731234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 5881a19da0dSRichard Henderson { 58931234768SRichard Henderson nullify_over(ctx); 5906fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 591ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 59231234768SRichard Henderson gen_excp(ctx, exc); 59331234768SRichard Henderson return nullify_end(ctx); 5941a19da0dSRichard Henderson } 5951a19da0dSRichard Henderson 59631234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 59761766fe9SRichard Henderson { 59831234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 59961766fe9SRichard Henderson } 60061766fe9SRichard Henderson 60140f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 60240f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 60340f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 60440f9f908SRichard Henderson #else 605e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 606e1b5a5edSRichard Henderson do { \ 607e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 60831234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 609e1b5a5edSRichard Henderson } \ 610e1b5a5edSRichard Henderson } while (0) 61140f9f908SRichard Henderson #endif 612e1b5a5edSRichard Henderson 613c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest) 61461766fe9SRichard Henderson { 61557f91498SRichard Henderson return translator_use_goto_tb(&ctx->base, dest); 61661766fe9SRichard Henderson } 61761766fe9SRichard Henderson 618129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 619129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 620129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 621129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 622129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 623129e9cc3SRichard Henderson { 624129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 625129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 626129e9cc3SRichard Henderson } 627129e9cc3SRichard Henderson 62861766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 629c53e401eSRichard Henderson uint64_t f, uint64_t b) 63061766fe9SRichard Henderson { 63161766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 63261766fe9SRichard Henderson tcg_gen_goto_tb(which); 633a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL); 634a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL); 63507ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 63661766fe9SRichard Henderson } else { 637741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b); 638741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var); 6397f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 64061766fe9SRichard Henderson } 64161766fe9SRichard Henderson } 64261766fe9SRichard Henderson 643b47a4a02SSven Schnelle static bool cond_need_sv(int c) 644b47a4a02SSven Schnelle { 645b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 646b47a4a02SSven Schnelle } 647b47a4a02SSven Schnelle 648b47a4a02SSven Schnelle static bool cond_need_cb(int c) 649b47a4a02SSven Schnelle { 650b47a4a02SSven Schnelle return c == 4 || c == 5; 651b47a4a02SSven Schnelle } 652b47a4a02SSven Schnelle 6536fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */ 65472ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d) 65572ca8753SRichard Henderson { 656c53e401eSRichard Henderson return !(ctx->is_pa20 && d); 65772ca8753SRichard Henderson } 65872ca8753SRichard Henderson 659b47a4a02SSven Schnelle /* 660b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 661b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 662b47a4a02SSven Schnelle */ 663b2167459SRichard Henderson 664a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 6656fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv) 666b2167459SRichard Henderson { 667b2167459SRichard Henderson DisasCond cond; 6686fd0c7bcSRichard Henderson TCGv_i64 tmp; 669b2167459SRichard Henderson 670b2167459SRichard Henderson switch (cf >> 1) { 671b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 672b2167459SRichard Henderson cond = cond_make_f(); 673b2167459SRichard Henderson break; 674b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 675a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 676aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6776fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 678a751eb31SRichard Henderson res = tmp; 679a751eb31SRichard Henderson } 680b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 681b2167459SRichard Henderson break; 682b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 683aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6846fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 685a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 6866fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, tmp); 687a751eb31SRichard Henderson } 688b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_LT, tmp); 689b2167459SRichard Henderson break; 690b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 691b47a4a02SSven Schnelle /* 692b47a4a02SSven Schnelle * Simplify: 693b47a4a02SSven Schnelle * (N ^ V) | Z 694b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 695b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 696b47a4a02SSven Schnelle * (~(res ^ sv) >= 0) | !res 697b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31) | !res 698b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31 & res) 699b47a4a02SSven Schnelle */ 700aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7016fd0c7bcSRichard Henderson tcg_gen_eqv_i64(tmp, res, sv); 702a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7036fd0c7bcSRichard Henderson tcg_gen_sextract_i64(tmp, tmp, 31, 1); 7046fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 7056fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 706a751eb31SRichard Henderson } else { 7076fd0c7bcSRichard Henderson tcg_gen_sari_i64(tmp, tmp, 63); 7086fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 709a751eb31SRichard Henderson } 710b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 711b2167459SRichard Henderson break; 712b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 713a751eb31SRichard Henderson /* Only bit 0 of cb_msb is ever set. */ 714b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 715b2167459SRichard Henderson break; 716b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 717aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7186fd0c7bcSRichard Henderson tcg_gen_neg_i64(tmp, cb_msb); 7196fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 720a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7216fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 722a751eb31SRichard Henderson } 723b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 724b2167459SRichard Henderson break; 725b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 726a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 727aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7286fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, sv); 729a751eb31SRichard Henderson sv = tmp; 730a751eb31SRichard Henderson } 731b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 732b2167459SRichard Henderson break; 733b2167459SRichard Henderson case 7: /* OD / EV */ 734aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7356fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, res, 1); 736b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_NE, tmp); 737b2167459SRichard Henderson break; 738b2167459SRichard Henderson default: 739b2167459SRichard Henderson g_assert_not_reached(); 740b2167459SRichard Henderson } 741b2167459SRichard Henderson if (cf & 1) { 742b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 743b2167459SRichard Henderson } 744b2167459SRichard Henderson 745b2167459SRichard Henderson return cond; 746b2167459SRichard Henderson } 747b2167459SRichard Henderson 748b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 749b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 750b2167459SRichard Henderson deleted as unused. */ 751b2167459SRichard Henderson 7524fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 7536fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 7546fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 755b2167459SRichard Henderson { 7564fe9533aSRichard Henderson TCGCond tc; 7574fe9533aSRichard Henderson bool ext_uns; 758b2167459SRichard Henderson 759b2167459SRichard Henderson switch (cf >> 1) { 760b2167459SRichard Henderson case 1: /* = / <> */ 7614fe9533aSRichard Henderson tc = TCG_COND_EQ; 7624fe9533aSRichard Henderson ext_uns = true; 763b2167459SRichard Henderson break; 764b2167459SRichard Henderson case 2: /* < / >= */ 7654fe9533aSRichard Henderson tc = TCG_COND_LT; 7664fe9533aSRichard Henderson ext_uns = false; 767b2167459SRichard Henderson break; 768b2167459SRichard Henderson case 3: /* <= / > */ 7694fe9533aSRichard Henderson tc = TCG_COND_LE; 7704fe9533aSRichard Henderson ext_uns = false; 771b2167459SRichard Henderson break; 772b2167459SRichard Henderson case 4: /* << / >>= */ 7734fe9533aSRichard Henderson tc = TCG_COND_LTU; 7744fe9533aSRichard Henderson ext_uns = true; 775b2167459SRichard Henderson break; 776b2167459SRichard Henderson case 5: /* <<= / >> */ 7774fe9533aSRichard Henderson tc = TCG_COND_LEU; 7784fe9533aSRichard Henderson ext_uns = true; 779b2167459SRichard Henderson break; 780b2167459SRichard Henderson default: 781a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 782b2167459SRichard Henderson } 783b2167459SRichard Henderson 7844fe9533aSRichard Henderson if (cf & 1) { 7854fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 7864fe9533aSRichard Henderson } 7874fe9533aSRichard Henderson if (cond_need_ext(ctx, d)) { 788aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 789aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 7904fe9533aSRichard Henderson 7914fe9533aSRichard Henderson if (ext_uns) { 7926fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 7936fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 7944fe9533aSRichard Henderson } else { 7956fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 7966fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 7974fe9533aSRichard Henderson } 7984fe9533aSRichard Henderson return cond_make_tmp(tc, t1, t2); 7994fe9533aSRichard Henderson } 8004fe9533aSRichard Henderson return cond_make(tc, in1, in2); 801b2167459SRichard Henderson } 802b2167459SRichard Henderson 803df0232feSRichard Henderson /* 804df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 805df0232feSRichard Henderson * computed, and use of them is undefined. 806df0232feSRichard Henderson * 807df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 808df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 809df0232feSRichard Henderson * how cases c={2,3} are treated. 810df0232feSRichard Henderson */ 811b2167459SRichard Henderson 812b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 8136fd0c7bcSRichard Henderson TCGv_i64 res) 814b2167459SRichard Henderson { 815b5af8423SRichard Henderson TCGCond tc; 816b5af8423SRichard Henderson bool ext_uns; 817a751eb31SRichard Henderson 818df0232feSRichard Henderson switch (cf) { 819df0232feSRichard Henderson case 0: /* never */ 820df0232feSRichard Henderson case 9: /* undef, C */ 821df0232feSRichard Henderson case 11: /* undef, C & !Z */ 822df0232feSRichard Henderson case 12: /* undef, V */ 823df0232feSRichard Henderson return cond_make_f(); 824df0232feSRichard Henderson 825df0232feSRichard Henderson case 1: /* true */ 826df0232feSRichard Henderson case 8: /* undef, !C */ 827df0232feSRichard Henderson case 10: /* undef, !C | Z */ 828df0232feSRichard Henderson case 13: /* undef, !V */ 829df0232feSRichard Henderson return cond_make_t(); 830df0232feSRichard Henderson 831df0232feSRichard Henderson case 2: /* == */ 832b5af8423SRichard Henderson tc = TCG_COND_EQ; 833b5af8423SRichard Henderson ext_uns = true; 834b5af8423SRichard Henderson break; 835df0232feSRichard Henderson case 3: /* <> */ 836b5af8423SRichard Henderson tc = TCG_COND_NE; 837b5af8423SRichard Henderson ext_uns = true; 838b5af8423SRichard Henderson break; 839df0232feSRichard Henderson case 4: /* < */ 840b5af8423SRichard Henderson tc = TCG_COND_LT; 841b5af8423SRichard Henderson ext_uns = false; 842b5af8423SRichard Henderson break; 843df0232feSRichard Henderson case 5: /* >= */ 844b5af8423SRichard Henderson tc = TCG_COND_GE; 845b5af8423SRichard Henderson ext_uns = false; 846b5af8423SRichard Henderson break; 847df0232feSRichard Henderson case 6: /* <= */ 848b5af8423SRichard Henderson tc = TCG_COND_LE; 849b5af8423SRichard Henderson ext_uns = false; 850b5af8423SRichard Henderson break; 851df0232feSRichard Henderson case 7: /* > */ 852b5af8423SRichard Henderson tc = TCG_COND_GT; 853b5af8423SRichard Henderson ext_uns = false; 854b5af8423SRichard Henderson break; 855df0232feSRichard Henderson 856df0232feSRichard Henderson case 14: /* OD */ 857df0232feSRichard Henderson case 15: /* EV */ 858a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, NULL); 859df0232feSRichard Henderson 860df0232feSRichard Henderson default: 861df0232feSRichard Henderson g_assert_not_reached(); 862b2167459SRichard Henderson } 863b5af8423SRichard Henderson 864b5af8423SRichard Henderson if (cond_need_ext(ctx, d)) { 865aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 866b5af8423SRichard Henderson 867b5af8423SRichard Henderson if (ext_uns) { 8686fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 869b5af8423SRichard Henderson } else { 8706fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 871b5af8423SRichard Henderson } 872b5af8423SRichard Henderson return cond_make_0_tmp(tc, tmp); 873b5af8423SRichard Henderson } 874b5af8423SRichard Henderson return cond_make_0(tc, res); 875b2167459SRichard Henderson } 876b2167459SRichard Henderson 87798cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 87898cd9ca7SRichard Henderson 8794fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 8806fd0c7bcSRichard Henderson TCGv_i64 res) 88198cd9ca7SRichard Henderson { 88298cd9ca7SRichard Henderson unsigned c, f; 88398cd9ca7SRichard Henderson 88498cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 88598cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 88698cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 88798cd9ca7SRichard Henderson c = orig & 3; 88898cd9ca7SRichard Henderson if (c == 3) { 88998cd9ca7SRichard Henderson c = 7; 89098cd9ca7SRichard Henderson } 89198cd9ca7SRichard Henderson f = (orig & 4) / 4; 89298cd9ca7SRichard Henderson 893b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 89498cd9ca7SRichard Henderson } 89598cd9ca7SRichard Henderson 896b2167459SRichard Henderson /* Similar, but for unit conditions. */ 897b2167459SRichard Henderson 8986fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res, 8996fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 900b2167459SRichard Henderson { 901b2167459SRichard Henderson DisasCond cond; 9026fd0c7bcSRichard Henderson TCGv_i64 tmp, cb = NULL; 903c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 904b2167459SRichard Henderson 905b2167459SRichard Henderson if (cf & 8) { 906b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 907b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 908b2167459SRichard Henderson * leaves us with carry bits spread across two words. 909b2167459SRichard Henderson */ 910aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 911aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9126fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, in1, in2); 9136fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, in1, in2); 9146fd0c7bcSRichard Henderson tcg_gen_andc_i64(cb, cb, res); 9156fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, cb, tmp); 916b2167459SRichard Henderson } 917b2167459SRichard Henderson 918b2167459SRichard Henderson switch (cf >> 1) { 919b2167459SRichard Henderson case 0: /* never / TR */ 920b2167459SRichard Henderson case 1: /* undefined */ 921b2167459SRichard Henderson case 5: /* undefined */ 922b2167459SRichard Henderson cond = cond_make_f(); 923b2167459SRichard Henderson break; 924b2167459SRichard Henderson 925b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 926b2167459SRichard Henderson /* See hasless(v,1) from 927b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 928b2167459SRichard Henderson */ 929aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9306fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u); 9316fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9326fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u); 933b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 934b2167459SRichard Henderson break; 935b2167459SRichard Henderson 936b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 937aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9386fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u); 9396fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9406fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u); 941b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 942b2167459SRichard Henderson break; 943b2167459SRichard Henderson 944b2167459SRichard Henderson case 4: /* SDC / NDC */ 9456fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u); 946b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 947b2167459SRichard Henderson break; 948b2167459SRichard Henderson 949b2167459SRichard Henderson case 6: /* SBC / NBC */ 9506fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u); 951b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 952b2167459SRichard Henderson break; 953b2167459SRichard Henderson 954b2167459SRichard Henderson case 7: /* SHC / NHC */ 9556fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u); 956b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 957b2167459SRichard Henderson break; 958b2167459SRichard Henderson 959b2167459SRichard Henderson default: 960b2167459SRichard Henderson g_assert_not_reached(); 961b2167459SRichard Henderson } 962b2167459SRichard Henderson if (cf & 1) { 963b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 964b2167459SRichard Henderson } 965b2167459SRichard Henderson 966b2167459SRichard Henderson return cond; 967b2167459SRichard Henderson } 968b2167459SRichard Henderson 9696fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 9706fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 97172ca8753SRichard Henderson { 97272ca8753SRichard Henderson if (cond_need_ext(ctx, d)) { 973aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 9746fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 97572ca8753SRichard Henderson return t; 97672ca8753SRichard Henderson } 97772ca8753SRichard Henderson return cb_msb; 97872ca8753SRichard Henderson } 97972ca8753SRichard Henderson 9806fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 98172ca8753SRichard Henderson { 98272ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 98372ca8753SRichard Henderson } 98472ca8753SRichard Henderson 985b2167459SRichard Henderson /* Compute signed overflow for addition. */ 9866fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 9876fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 988b2167459SRichard Henderson { 989aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 990aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 991b2167459SRichard Henderson 9926fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 9936fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 9946fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 995b2167459SRichard Henderson 996b2167459SRichard Henderson return sv; 997b2167459SRichard Henderson } 998b2167459SRichard Henderson 999b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 10006fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 10016fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1002b2167459SRichard Henderson { 1003aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1004aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1005b2167459SRichard Henderson 10066fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10076fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10086fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 1009b2167459SRichard Henderson 1010b2167459SRichard Henderson return sv; 1011b2167459SRichard Henderson } 1012b2167459SRichard Henderson 10136fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 10146fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1015faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1016b2167459SRichard Henderson { 10176fd0c7bcSRichard Henderson TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp; 1018b2167459SRichard Henderson unsigned c = cf >> 1; 1019b2167459SRichard Henderson DisasCond cond; 1020b2167459SRichard Henderson 1021aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1022f764718dSRichard Henderson cb = NULL; 1023f764718dSRichard Henderson cb_msb = NULL; 1024bdcccc17SRichard Henderson cb_cond = NULL; 1025b2167459SRichard Henderson 1026b2167459SRichard Henderson if (shift) { 1027aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10286fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1029b2167459SRichard Henderson in1 = tmp; 1030b2167459SRichard Henderson } 1031b2167459SRichard Henderson 1032b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1033aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1034aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1035bdcccc17SRichard Henderson 1036a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1037b2167459SRichard Henderson if (is_c) { 10386fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1039a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1040b2167459SRichard Henderson } 10416fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 10426fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1043bdcccc17SRichard Henderson if (cond_need_cb(c)) { 1044bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 1045b2167459SRichard Henderson } 1046b2167459SRichard Henderson } else { 10476fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1048b2167459SRichard Henderson if (is_c) { 10496fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1050b2167459SRichard Henderson } 1051b2167459SRichard Henderson } 1052b2167459SRichard Henderson 1053b2167459SRichard Henderson /* Compute signed overflow if required. */ 1054f764718dSRichard Henderson sv = NULL; 1055b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1056b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 1057b2167459SRichard Henderson if (is_tsv) { 1058b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 1059ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1060b2167459SRichard Henderson } 1061b2167459SRichard Henderson } 1062b2167459SRichard Henderson 1063b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1064a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, cb_cond, sv); 1065b2167459SRichard Henderson if (is_tc) { 1066aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10676fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1068ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1069b2167459SRichard Henderson } 1070b2167459SRichard Henderson 1071b2167459SRichard Henderson /* Write back the result. */ 1072b2167459SRichard Henderson if (!is_l) { 1073b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1074b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1075b2167459SRichard Henderson } 1076b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1077b2167459SRichard Henderson 1078b2167459SRichard Henderson /* Install the new nullification. */ 1079b2167459SRichard Henderson cond_free(&ctx->null_cond); 1080b2167459SRichard Henderson ctx->null_cond = cond; 1081b2167459SRichard Henderson } 1082b2167459SRichard Henderson 1083faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 10840c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 10850c982a28SRichard Henderson { 10866fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 10870c982a28SRichard Henderson 10880c982a28SRichard Henderson if (a->cf) { 10890c982a28SRichard Henderson nullify_over(ctx); 10900c982a28SRichard Henderson } 10910c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 10920c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1093faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1094faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 10950c982a28SRichard Henderson return nullify_end(ctx); 10960c982a28SRichard Henderson } 10970c982a28SRichard Henderson 10980588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 10990588e061SRichard Henderson bool is_tsv, bool is_tc) 11000588e061SRichard Henderson { 11016fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11020588e061SRichard Henderson 11030588e061SRichard Henderson if (a->cf) { 11040588e061SRichard Henderson nullify_over(ctx); 11050588e061SRichard Henderson } 11066fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11070588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1108faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1109faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 11100588e061SRichard Henderson return nullify_end(ctx); 11110588e061SRichard Henderson } 11120588e061SRichard Henderson 11136fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 11146fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 111563c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1116b2167459SRichard Henderson { 1117a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1118b2167459SRichard Henderson unsigned c = cf >> 1; 1119b2167459SRichard Henderson DisasCond cond; 1120b2167459SRichard Henderson 1121aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1122aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1123aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1124b2167459SRichard Henderson 1125b2167459SRichard Henderson if (is_b) { 1126b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 11276fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1128a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1129a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1130a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 11316fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 11326fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1133b2167459SRichard Henderson } else { 1134bdcccc17SRichard Henderson /* 1135bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1136bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1137bdcccc17SRichard Henderson */ 11386fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1139a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 11406fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 11416fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1142b2167459SRichard Henderson } 1143b2167459SRichard Henderson 1144b2167459SRichard Henderson /* Compute signed overflow if required. */ 1145f764718dSRichard Henderson sv = NULL; 1146b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1147b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1148b2167459SRichard Henderson if (is_tsv) { 1149ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1150b2167459SRichard Henderson } 1151b2167459SRichard Henderson } 1152b2167459SRichard Henderson 1153b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1154b2167459SRichard Henderson if (!is_b) { 11554fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1156b2167459SRichard Henderson } else { 1157a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1158b2167459SRichard Henderson } 1159b2167459SRichard Henderson 1160b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1161b2167459SRichard Henderson if (is_tc) { 1162aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11636fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1164ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1165b2167459SRichard Henderson } 1166b2167459SRichard Henderson 1167b2167459SRichard Henderson /* Write back the result. */ 1168b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1169b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1170b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1171b2167459SRichard Henderson 1172b2167459SRichard Henderson /* Install the new nullification. */ 1173b2167459SRichard Henderson cond_free(&ctx->null_cond); 1174b2167459SRichard Henderson ctx->null_cond = cond; 1175b2167459SRichard Henderson } 1176b2167459SRichard Henderson 117763c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 11780c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 11790c982a28SRichard Henderson { 11806fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 11810c982a28SRichard Henderson 11820c982a28SRichard Henderson if (a->cf) { 11830c982a28SRichard Henderson nullify_over(ctx); 11840c982a28SRichard Henderson } 11850c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 11860c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 118763c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 11880c982a28SRichard Henderson return nullify_end(ctx); 11890c982a28SRichard Henderson } 11900c982a28SRichard Henderson 11910588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 11920588e061SRichard Henderson { 11936fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11940588e061SRichard Henderson 11950588e061SRichard Henderson if (a->cf) { 11960588e061SRichard Henderson nullify_over(ctx); 11970588e061SRichard Henderson } 11986fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11990588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 120063c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 120163c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 12020588e061SRichard Henderson return nullify_end(ctx); 12030588e061SRichard Henderson } 12040588e061SRichard Henderson 12056fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12066fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1207b2167459SRichard Henderson { 12086fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1209b2167459SRichard Henderson DisasCond cond; 1210b2167459SRichard Henderson 1211aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 12126fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1213b2167459SRichard Henderson 1214b2167459SRichard Henderson /* Compute signed overflow if required. */ 1215f764718dSRichard Henderson sv = NULL; 1216b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1217b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1218b2167459SRichard Henderson } 1219b2167459SRichard Henderson 1220b2167459SRichard Henderson /* Form the condition for the compare. */ 12214fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1222b2167459SRichard Henderson 1223b2167459SRichard Henderson /* Clear. */ 12246fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1225b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1226b2167459SRichard Henderson 1227b2167459SRichard Henderson /* Install the new nullification. */ 1228b2167459SRichard Henderson cond_free(&ctx->null_cond); 1229b2167459SRichard Henderson ctx->null_cond = cond; 1230b2167459SRichard Henderson } 1231b2167459SRichard Henderson 12326fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12336fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 12346fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1235b2167459SRichard Henderson { 12366fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1237b2167459SRichard Henderson 1238b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1239b2167459SRichard Henderson fn(dest, in1, in2); 1240b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1241b2167459SRichard Henderson 1242b2167459SRichard Henderson /* Install the new nullification. */ 1243b2167459SRichard Henderson cond_free(&ctx->null_cond); 1244b2167459SRichard Henderson if (cf) { 1245b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1246b2167459SRichard Henderson } 1247b2167459SRichard Henderson } 1248b2167459SRichard Henderson 1249fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12506fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 12510c982a28SRichard Henderson { 12526fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12530c982a28SRichard Henderson 12540c982a28SRichard Henderson if (a->cf) { 12550c982a28SRichard Henderson nullify_over(ctx); 12560c982a28SRichard Henderson } 12570c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12580c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1259fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 12600c982a28SRichard Henderson return nullify_end(ctx); 12610c982a28SRichard Henderson } 12620c982a28SRichard Henderson 12636fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12646fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, bool is_tc, 12656fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1266b2167459SRichard Henderson { 12676fd0c7bcSRichard Henderson TCGv_i64 dest; 1268b2167459SRichard Henderson DisasCond cond; 1269b2167459SRichard Henderson 1270b2167459SRichard Henderson if (cf == 0) { 1271b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 1272b2167459SRichard Henderson fn(dest, in1, in2); 1273b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1274b2167459SRichard Henderson cond_free(&ctx->null_cond); 1275b2167459SRichard Henderson } else { 1276aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1277b2167459SRichard Henderson fn(dest, in1, in2); 1278b2167459SRichard Henderson 127959963d8fSRichard Henderson cond = do_unit_cond(cf, d, dest, in1, in2); 1280b2167459SRichard Henderson 1281b2167459SRichard Henderson if (is_tc) { 1282aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 12836fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1284ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1285b2167459SRichard Henderson } 1286b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1287b2167459SRichard Henderson 1288b2167459SRichard Henderson cond_free(&ctx->null_cond); 1289b2167459SRichard Henderson ctx->null_cond = cond; 1290b2167459SRichard Henderson } 1291b2167459SRichard Henderson } 1292b2167459SRichard Henderson 129386f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 12948d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 12958d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 12968d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 12978d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 12986fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 129986f8d05fSRichard Henderson { 130086f8d05fSRichard Henderson TCGv_ptr ptr; 13016fd0c7bcSRichard Henderson TCGv_i64 tmp; 130286f8d05fSRichard Henderson TCGv_i64 spc; 130386f8d05fSRichard Henderson 130486f8d05fSRichard Henderson if (sp != 0) { 13058d6ae7fbSRichard Henderson if (sp < 0) { 13068d6ae7fbSRichard Henderson sp = ~sp; 13078d6ae7fbSRichard Henderson } 13086fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 13098d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 13108d6ae7fbSRichard Henderson return spc; 131186f8d05fSRichard Henderson } 1312494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1313494737b7SRichard Henderson return cpu_srH; 1314494737b7SRichard Henderson } 131586f8d05fSRichard Henderson 131686f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1317aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 13186fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 131986f8d05fSRichard Henderson 1320698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 13216fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 13226fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 13236fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 132486f8d05fSRichard Henderson 1325ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 132686f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 132786f8d05fSRichard Henderson 132886f8d05fSRichard Henderson return spc; 132986f8d05fSRichard Henderson } 133086f8d05fSRichard Henderson #endif 133186f8d05fSRichard Henderson 13326fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1333c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 133486f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 133586f8d05fSRichard Henderson { 13366fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 13376fd0c7bcSRichard Henderson TCGv_i64 ofs; 13386fd0c7bcSRichard Henderson TCGv_i64 addr; 133986f8d05fSRichard Henderson 1340f5b5c857SRichard Henderson set_insn_breg(ctx, rb); 1341f5b5c857SRichard Henderson 134286f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 134386f8d05fSRichard Henderson if (rx) { 1344aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13456fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 13466fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 134786f8d05fSRichard Henderson } else if (disp || modify) { 1348aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13496fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 135086f8d05fSRichard Henderson } else { 135186f8d05fSRichard Henderson ofs = base; 135286f8d05fSRichard Henderson } 135386f8d05fSRichard Henderson 135486f8d05fSRichard Henderson *pofs = ofs; 13556fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 1356d265360fSRichard Henderson tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx)); 1357698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 135886f8d05fSRichard Henderson if (!is_phys) { 1359d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 136086f8d05fSRichard Henderson } 136186f8d05fSRichard Henderson #endif 136286f8d05fSRichard Henderson } 136386f8d05fSRichard Henderson 136496d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 136596d6407fSRichard Henderson * < 0 for pre-modify, 136696d6407fSRichard Henderson * > 0 for post-modify, 136796d6407fSRichard Henderson * = 0 for no base register update. 136896d6407fSRichard Henderson */ 136996d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1370c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 137114776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 137296d6407fSRichard Henderson { 13736fd0c7bcSRichard Henderson TCGv_i64 ofs; 13746fd0c7bcSRichard Henderson TCGv_i64 addr; 137596d6407fSRichard Henderson 137696d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 137796d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 137896d6407fSRichard Henderson 137986f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 138017fe594cSRichard Henderson MMU_DISABLED(ctx)); 1381c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 138286f8d05fSRichard Henderson if (modify) { 138386f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 138496d6407fSRichard Henderson } 138596d6407fSRichard Henderson } 138696d6407fSRichard Henderson 138796d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1388c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 138914776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 139096d6407fSRichard Henderson { 13916fd0c7bcSRichard Henderson TCGv_i64 ofs; 13926fd0c7bcSRichard Henderson TCGv_i64 addr; 139396d6407fSRichard Henderson 139496d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 139596d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 139696d6407fSRichard Henderson 139786f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 139817fe594cSRichard Henderson MMU_DISABLED(ctx)); 1399217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 140086f8d05fSRichard Henderson if (modify) { 140186f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 140296d6407fSRichard Henderson } 140396d6407fSRichard Henderson } 140496d6407fSRichard Henderson 140596d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1406c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 140714776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 140896d6407fSRichard Henderson { 14096fd0c7bcSRichard Henderson TCGv_i64 ofs; 14106fd0c7bcSRichard Henderson TCGv_i64 addr; 141196d6407fSRichard Henderson 141296d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 141396d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 141496d6407fSRichard Henderson 141586f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 141617fe594cSRichard Henderson MMU_DISABLED(ctx)); 1417217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 141886f8d05fSRichard Henderson if (modify) { 141986f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 142096d6407fSRichard Henderson } 142196d6407fSRichard Henderson } 142296d6407fSRichard Henderson 142396d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1424c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 142514776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 142696d6407fSRichard Henderson { 14276fd0c7bcSRichard Henderson TCGv_i64 ofs; 14286fd0c7bcSRichard Henderson TCGv_i64 addr; 142996d6407fSRichard Henderson 143096d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 143196d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 143296d6407fSRichard Henderson 143386f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 143417fe594cSRichard Henderson MMU_DISABLED(ctx)); 1435217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 143686f8d05fSRichard Henderson if (modify) { 143786f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 143896d6407fSRichard Henderson } 143996d6407fSRichard Henderson } 144096d6407fSRichard Henderson 14411cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1442c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 144314776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 144496d6407fSRichard Henderson { 14456fd0c7bcSRichard Henderson TCGv_i64 dest; 144696d6407fSRichard Henderson 144796d6407fSRichard Henderson nullify_over(ctx); 144896d6407fSRichard Henderson 144996d6407fSRichard Henderson if (modify == 0) { 145096d6407fSRichard Henderson /* No base register update. */ 145196d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 145296d6407fSRichard Henderson } else { 145396d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1454aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 145596d6407fSRichard Henderson } 14566fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 145796d6407fSRichard Henderson save_gpr(ctx, rt, dest); 145896d6407fSRichard Henderson 14591cd012a5SRichard Henderson return nullify_end(ctx); 146096d6407fSRichard Henderson } 146196d6407fSRichard Henderson 1462740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1463c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 146486f8d05fSRichard Henderson unsigned sp, int modify) 146596d6407fSRichard Henderson { 146696d6407fSRichard Henderson TCGv_i32 tmp; 146796d6407fSRichard Henderson 146896d6407fSRichard Henderson nullify_over(ctx); 146996d6407fSRichard Henderson 147096d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 147186f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 147296d6407fSRichard Henderson save_frw_i32(rt, tmp); 147396d6407fSRichard Henderson 147496d6407fSRichard Henderson if (rt == 0) { 1475ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 147696d6407fSRichard Henderson } 147796d6407fSRichard Henderson 1478740038d7SRichard Henderson return nullify_end(ctx); 147996d6407fSRichard Henderson } 148096d6407fSRichard Henderson 1481740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1482740038d7SRichard Henderson { 1483740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1484740038d7SRichard Henderson a->disp, a->sp, a->m); 1485740038d7SRichard Henderson } 1486740038d7SRichard Henderson 1487740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1488c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 148986f8d05fSRichard Henderson unsigned sp, int modify) 149096d6407fSRichard Henderson { 149196d6407fSRichard Henderson TCGv_i64 tmp; 149296d6407fSRichard Henderson 149396d6407fSRichard Henderson nullify_over(ctx); 149496d6407fSRichard Henderson 149596d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1496fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 149796d6407fSRichard Henderson save_frd(rt, tmp); 149896d6407fSRichard Henderson 149996d6407fSRichard Henderson if (rt == 0) { 1500ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 150196d6407fSRichard Henderson } 150296d6407fSRichard Henderson 1503740038d7SRichard Henderson return nullify_end(ctx); 1504740038d7SRichard Henderson } 1505740038d7SRichard Henderson 1506740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1507740038d7SRichard Henderson { 1508740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1509740038d7SRichard Henderson a->disp, a->sp, a->m); 151096d6407fSRichard Henderson } 151196d6407fSRichard Henderson 15121cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1513c53e401eSRichard Henderson int64_t disp, unsigned sp, 151414776ab5STony Nguyen int modify, MemOp mop) 151596d6407fSRichard Henderson { 151696d6407fSRichard Henderson nullify_over(ctx); 15176fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 15181cd012a5SRichard Henderson return nullify_end(ctx); 151996d6407fSRichard Henderson } 152096d6407fSRichard Henderson 1521740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1522c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 152386f8d05fSRichard Henderson unsigned sp, int modify) 152496d6407fSRichard Henderson { 152596d6407fSRichard Henderson TCGv_i32 tmp; 152696d6407fSRichard Henderson 152796d6407fSRichard Henderson nullify_over(ctx); 152896d6407fSRichard Henderson 152996d6407fSRichard Henderson tmp = load_frw_i32(rt); 153086f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 153196d6407fSRichard Henderson 1532740038d7SRichard Henderson return nullify_end(ctx); 153396d6407fSRichard Henderson } 153496d6407fSRichard Henderson 1535740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1536740038d7SRichard Henderson { 1537740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1538740038d7SRichard Henderson a->disp, a->sp, a->m); 1539740038d7SRichard Henderson } 1540740038d7SRichard Henderson 1541740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1542c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 154386f8d05fSRichard Henderson unsigned sp, int modify) 154496d6407fSRichard Henderson { 154596d6407fSRichard Henderson TCGv_i64 tmp; 154696d6407fSRichard Henderson 154796d6407fSRichard Henderson nullify_over(ctx); 154896d6407fSRichard Henderson 154996d6407fSRichard Henderson tmp = load_frd(rt); 1550fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 155196d6407fSRichard Henderson 1552740038d7SRichard Henderson return nullify_end(ctx); 1553740038d7SRichard Henderson } 1554740038d7SRichard Henderson 1555740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1556740038d7SRichard Henderson { 1557740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1558740038d7SRichard Henderson a->disp, a->sp, a->m); 155996d6407fSRichard Henderson } 156096d6407fSRichard Henderson 15611ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1562ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1563ebe9383cSRichard Henderson { 1564ebe9383cSRichard Henderson TCGv_i32 tmp; 1565ebe9383cSRichard Henderson 1566ebe9383cSRichard Henderson nullify_over(ctx); 1567ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1568ebe9383cSRichard Henderson 1569ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1570ebe9383cSRichard Henderson 1571ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 15721ca74648SRichard Henderson return nullify_end(ctx); 1573ebe9383cSRichard Henderson } 1574ebe9383cSRichard Henderson 15751ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1576ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1577ebe9383cSRichard Henderson { 1578ebe9383cSRichard Henderson TCGv_i32 dst; 1579ebe9383cSRichard Henderson TCGv_i64 src; 1580ebe9383cSRichard Henderson 1581ebe9383cSRichard Henderson nullify_over(ctx); 1582ebe9383cSRichard Henderson src = load_frd(ra); 1583ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1584ebe9383cSRichard Henderson 1585ad75a51eSRichard Henderson func(dst, tcg_env, src); 1586ebe9383cSRichard Henderson 1587ebe9383cSRichard Henderson save_frw_i32(rt, dst); 15881ca74648SRichard Henderson return nullify_end(ctx); 1589ebe9383cSRichard Henderson } 1590ebe9383cSRichard Henderson 15911ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1592ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1593ebe9383cSRichard Henderson { 1594ebe9383cSRichard Henderson TCGv_i64 tmp; 1595ebe9383cSRichard Henderson 1596ebe9383cSRichard Henderson nullify_over(ctx); 1597ebe9383cSRichard Henderson tmp = load_frd0(ra); 1598ebe9383cSRichard Henderson 1599ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1600ebe9383cSRichard Henderson 1601ebe9383cSRichard Henderson save_frd(rt, tmp); 16021ca74648SRichard Henderson return nullify_end(ctx); 1603ebe9383cSRichard Henderson } 1604ebe9383cSRichard Henderson 16051ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1606ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1607ebe9383cSRichard Henderson { 1608ebe9383cSRichard Henderson TCGv_i32 src; 1609ebe9383cSRichard Henderson TCGv_i64 dst; 1610ebe9383cSRichard Henderson 1611ebe9383cSRichard Henderson nullify_over(ctx); 1612ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1613ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1614ebe9383cSRichard Henderson 1615ad75a51eSRichard Henderson func(dst, tcg_env, src); 1616ebe9383cSRichard Henderson 1617ebe9383cSRichard Henderson save_frd(rt, dst); 16181ca74648SRichard Henderson return nullify_end(ctx); 1619ebe9383cSRichard Henderson } 1620ebe9383cSRichard Henderson 16211ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1622ebe9383cSRichard Henderson unsigned ra, unsigned rb, 162331234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1624ebe9383cSRichard Henderson { 1625ebe9383cSRichard Henderson TCGv_i32 a, b; 1626ebe9383cSRichard Henderson 1627ebe9383cSRichard Henderson nullify_over(ctx); 1628ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1629ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1630ebe9383cSRichard Henderson 1631ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1632ebe9383cSRichard Henderson 1633ebe9383cSRichard Henderson save_frw_i32(rt, a); 16341ca74648SRichard Henderson return nullify_end(ctx); 1635ebe9383cSRichard Henderson } 1636ebe9383cSRichard Henderson 16371ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1638ebe9383cSRichard Henderson unsigned ra, unsigned rb, 163931234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1640ebe9383cSRichard Henderson { 1641ebe9383cSRichard Henderson TCGv_i64 a, b; 1642ebe9383cSRichard Henderson 1643ebe9383cSRichard Henderson nullify_over(ctx); 1644ebe9383cSRichard Henderson a = load_frd0(ra); 1645ebe9383cSRichard Henderson b = load_frd0(rb); 1646ebe9383cSRichard Henderson 1647ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1648ebe9383cSRichard Henderson 1649ebe9383cSRichard Henderson save_frd(rt, a); 16501ca74648SRichard Henderson return nullify_end(ctx); 1651ebe9383cSRichard Henderson } 1652ebe9383cSRichard Henderson 165398cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 165498cd9ca7SRichard Henderson have already had nullification handled. */ 1655c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest, 165698cd9ca7SRichard Henderson unsigned link, bool is_n) 165798cd9ca7SRichard Henderson { 165898cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 165998cd9ca7SRichard Henderson if (link != 0) { 1660741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 166198cd9ca7SRichard Henderson } 166298cd9ca7SRichard Henderson ctx->iaoq_n = dest; 166398cd9ca7SRichard Henderson if (is_n) { 166498cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 166598cd9ca7SRichard Henderson } 166698cd9ca7SRichard Henderson } else { 166798cd9ca7SRichard Henderson nullify_over(ctx); 166898cd9ca7SRichard Henderson 166998cd9ca7SRichard Henderson if (link != 0) { 1670741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 167198cd9ca7SRichard Henderson } 167298cd9ca7SRichard Henderson 167398cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 167498cd9ca7SRichard Henderson nullify_set(ctx, 0); 167598cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 167698cd9ca7SRichard Henderson } else { 167798cd9ca7SRichard Henderson nullify_set(ctx, is_n); 167898cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 167998cd9ca7SRichard Henderson } 168098cd9ca7SRichard Henderson 168131234768SRichard Henderson nullify_end(ctx); 168298cd9ca7SRichard Henderson 168398cd9ca7SRichard Henderson nullify_set(ctx, 0); 168498cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 168531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 168698cd9ca7SRichard Henderson } 168701afb7beSRichard Henderson return true; 168898cd9ca7SRichard Henderson } 168998cd9ca7SRichard Henderson 169098cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 169198cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1692c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 169398cd9ca7SRichard Henderson DisasCond *cond) 169498cd9ca7SRichard Henderson { 1695c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, disp); 169698cd9ca7SRichard Henderson TCGLabel *taken = NULL; 169798cd9ca7SRichard Henderson TCGCond c = cond->c; 169898cd9ca7SRichard Henderson bool n; 169998cd9ca7SRichard Henderson 170098cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 170198cd9ca7SRichard Henderson 170298cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 170398cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 170401afb7beSRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 170598cd9ca7SRichard Henderson } 170698cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 170701afb7beSRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 170898cd9ca7SRichard Henderson } 170998cd9ca7SRichard Henderson 171098cd9ca7SRichard Henderson taken = gen_new_label(); 17116fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 171298cd9ca7SRichard Henderson cond_free(cond); 171398cd9ca7SRichard Henderson 171498cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 171598cd9ca7SRichard Henderson n = is_n && disp < 0; 171698cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 171798cd9ca7SRichard Henderson nullify_set(ctx, 0); 1718a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 171998cd9ca7SRichard Henderson } else { 172098cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 172198cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 172298cd9ca7SRichard Henderson ctx->null_lab = NULL; 172398cd9ca7SRichard Henderson } 172498cd9ca7SRichard Henderson nullify_set(ctx, n); 1725c301f34eSRichard Henderson if (ctx->iaoq_n == -1) { 1726c301f34eSRichard Henderson /* The temporary iaoq_n_var died at the branch above. 1727c301f34eSRichard Henderson Regenerate it here instead of saving it. */ 17286fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 1729c301f34eSRichard Henderson } 1730a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 173198cd9ca7SRichard Henderson } 173298cd9ca7SRichard Henderson 173398cd9ca7SRichard Henderson gen_set_label(taken); 173498cd9ca7SRichard Henderson 173598cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 173698cd9ca7SRichard Henderson n = is_n && disp >= 0; 173798cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 173898cd9ca7SRichard Henderson nullify_set(ctx, 0); 1739a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, dest, dest + 4); 174098cd9ca7SRichard Henderson } else { 174198cd9ca7SRichard Henderson nullify_set(ctx, n); 1742a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 174398cd9ca7SRichard Henderson } 174498cd9ca7SRichard Henderson 174598cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 174698cd9ca7SRichard Henderson if (ctx->null_lab) { 174798cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 174898cd9ca7SRichard Henderson ctx->null_lab = NULL; 174931234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 175098cd9ca7SRichard Henderson } else { 175131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 175298cd9ca7SRichard Henderson } 175301afb7beSRichard Henderson return true; 175498cd9ca7SRichard Henderson } 175598cd9ca7SRichard Henderson 175698cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 175798cd9ca7SRichard Henderson nullification of the branch itself. */ 17586fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest, 175998cd9ca7SRichard Henderson unsigned link, bool is_n) 176098cd9ca7SRichard Henderson { 17616fd0c7bcSRichard Henderson TCGv_i64 a0, a1, next, tmp; 176298cd9ca7SRichard Henderson TCGCond c; 176398cd9ca7SRichard Henderson 176498cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 176598cd9ca7SRichard Henderson 176698cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 176798cd9ca7SRichard Henderson if (link != 0) { 1768741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 176998cd9ca7SRichard Henderson } 1770aac0f603SRichard Henderson next = tcg_temp_new_i64(); 17716fd0c7bcSRichard Henderson tcg_gen_mov_i64(next, dest); 177298cd9ca7SRichard Henderson if (is_n) { 1773c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1774a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next); 17756fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, next, 4); 1776a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 1777c301f34eSRichard Henderson nullify_set(ctx, 0); 177831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 177901afb7beSRichard Henderson return true; 1780c301f34eSRichard Henderson } 178198cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 178298cd9ca7SRichard Henderson } 1783c301f34eSRichard Henderson ctx->iaoq_n = -1; 1784c301f34eSRichard Henderson ctx->iaoq_n_var = next; 178598cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 178698cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 178798cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 17884137cb83SRichard Henderson tracepoint in effect). Since the goto_ptr that we must use 178998cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 179098cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 179198cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 179298cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 179398cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 179498cd9ca7SRichard Henderson 179598cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 179698cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 179798cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 1798a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest); 1799aac0f603SRichard Henderson next = tcg_temp_new_i64(); 18006fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, dest, 4); 1801a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 180298cd9ca7SRichard Henderson 180398cd9ca7SRichard Henderson nullify_over(ctx); 180498cd9ca7SRichard Henderson if (link != 0) { 18059a91dd84SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 180698cd9ca7SRichard Henderson } 18077f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 180801afb7beSRichard Henderson return nullify_end(ctx); 180998cd9ca7SRichard Henderson } else { 181098cd9ca7SRichard Henderson c = ctx->null_cond.c; 181198cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 181298cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 181398cd9ca7SRichard Henderson 1814aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 1815aac0f603SRichard Henderson next = tcg_temp_new_i64(); 181698cd9ca7SRichard Henderson 1817741322f4SRichard Henderson copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var); 18186fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest); 181998cd9ca7SRichard Henderson ctx->iaoq_n = -1; 182098cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 182198cd9ca7SRichard Henderson 182298cd9ca7SRichard Henderson if (link != 0) { 18236fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 182498cd9ca7SRichard Henderson } 182598cd9ca7SRichard Henderson 182698cd9ca7SRichard Henderson if (is_n) { 182798cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 182898cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 182998cd9ca7SRichard Henderson to the branch. */ 18306fd0c7bcSRichard Henderson tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1); 183198cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 183298cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 183398cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 183498cd9ca7SRichard Henderson } else { 183598cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 183698cd9ca7SRichard Henderson } 183798cd9ca7SRichard Henderson } 183801afb7beSRichard Henderson return true; 183998cd9ca7SRichard Henderson } 184098cd9ca7SRichard Henderson 1841660eefe1SRichard Henderson /* Implement 1842660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1843660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1844660eefe1SRichard Henderson * else 1845660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1846660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1847660eefe1SRichard Henderson */ 18486fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1849660eefe1SRichard Henderson { 18506fd0c7bcSRichard Henderson TCGv_i64 dest; 1851660eefe1SRichard Henderson switch (ctx->privilege) { 1852660eefe1SRichard Henderson case 0: 1853660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 1854660eefe1SRichard Henderson return offset; 1855660eefe1SRichard Henderson case 3: 1856993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 1857aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18586fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1859660eefe1SRichard Henderson break; 1860660eefe1SRichard Henderson default: 1861aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18626fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 18636fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 18646fd0c7bcSRichard Henderson tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset); 1865660eefe1SRichard Henderson break; 1866660eefe1SRichard Henderson } 1867660eefe1SRichard Henderson return dest; 1868660eefe1SRichard Henderson } 1869660eefe1SRichard Henderson 1870ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 18717ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 18727ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 18737ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 18747ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 18757ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 18767ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 18777ad439dfSRichard Henderson aforementioned BE. */ 187831234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 18797ad439dfSRichard Henderson { 18806fd0c7bcSRichard Henderson TCGv_i64 tmp; 1881a0180973SRichard Henderson 18827ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 18837ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 18848b81968cSMichael Tokarev next insn within the privileged page. */ 18857ad439dfSRichard Henderson switch (ctx->null_cond.c) { 18867ad439dfSRichard Henderson case TCG_COND_NEVER: 18877ad439dfSRichard Henderson break; 18887ad439dfSRichard Henderson case TCG_COND_ALWAYS: 18896fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 18907ad439dfSRichard Henderson goto do_sigill; 18917ad439dfSRichard Henderson default: 18927ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 18937ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 18947ad439dfSRichard Henderson g_assert_not_reached(); 18957ad439dfSRichard Henderson } 18967ad439dfSRichard Henderson 18977ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 18987ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 18997ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 19007ad439dfSRichard Henderson under such conditions. */ 19017ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 19027ad439dfSRichard Henderson goto do_sigill; 19037ad439dfSRichard Henderson } 19047ad439dfSRichard Henderson 1905ebd0e151SRichard Henderson switch (ctx->iaoq_f & -4) { 19067ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 19072986721dSRichard Henderson gen_excp_1(EXCP_IMP); 190831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 190931234768SRichard Henderson break; 19107ad439dfSRichard Henderson 19117ad439dfSRichard Henderson case 0xb0: /* LWS */ 19127ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 191331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 191431234768SRichard Henderson break; 19157ad439dfSRichard Henderson 19167ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 19176fd0c7bcSRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27])); 1918aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 19196fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_gr[31], 3); 1920a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 19216fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 1922a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 192331234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 192431234768SRichard Henderson break; 19257ad439dfSRichard Henderson 19267ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 19277ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 192831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 192931234768SRichard Henderson break; 19307ad439dfSRichard Henderson 19317ad439dfSRichard Henderson default: 19327ad439dfSRichard Henderson do_sigill: 19332986721dSRichard Henderson gen_excp_1(EXCP_ILL); 193431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 193531234768SRichard Henderson break; 19367ad439dfSRichard Henderson } 19377ad439dfSRichard Henderson } 1938ba1d0b44SRichard Henderson #endif 19397ad439dfSRichard Henderson 1940deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 1941b2167459SRichard Henderson { 1942b2167459SRichard Henderson cond_free(&ctx->null_cond); 194331234768SRichard Henderson return true; 1944b2167459SRichard Henderson } 1945b2167459SRichard Henderson 194640f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 194798a9cb79SRichard Henderson { 194831234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 194998a9cb79SRichard Henderson } 195098a9cb79SRichard Henderson 1951e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 195298a9cb79SRichard Henderson { 195398a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 195498a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 195598a9cb79SRichard Henderson 195698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 195731234768SRichard Henderson return true; 195898a9cb79SRichard Henderson } 195998a9cb79SRichard Henderson 1960c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 196198a9cb79SRichard Henderson { 1962c603e14aSRichard Henderson unsigned rt = a->t; 19636fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, rt); 19646fd0c7bcSRichard Henderson tcg_gen_movi_i64(tmp, ctx->iaoq_f); 196598a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 196698a9cb79SRichard Henderson 196798a9cb79SRichard Henderson cond_free(&ctx->null_cond); 196831234768SRichard Henderson return true; 196998a9cb79SRichard Henderson } 197098a9cb79SRichard Henderson 1971c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 197298a9cb79SRichard Henderson { 1973c603e14aSRichard Henderson unsigned rt = a->t; 1974c603e14aSRichard Henderson unsigned rs = a->sp; 197533423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 197698a9cb79SRichard Henderson 197733423472SRichard Henderson load_spr(ctx, t0, rs); 197833423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 197933423472SRichard Henderson 1980967662cdSRichard Henderson save_gpr(ctx, rt, t0); 198198a9cb79SRichard Henderson 198298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 198331234768SRichard Henderson return true; 198498a9cb79SRichard Henderson } 198598a9cb79SRichard Henderson 1986c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 198798a9cb79SRichard Henderson { 1988c603e14aSRichard Henderson unsigned rt = a->t; 1989c603e14aSRichard Henderson unsigned ctl = a->r; 19906fd0c7bcSRichard Henderson TCGv_i64 tmp; 199198a9cb79SRichard Henderson 199298a9cb79SRichard Henderson switch (ctl) { 199335136a77SRichard Henderson case CR_SAR: 1994c603e14aSRichard Henderson if (a->e == 0) { 199598a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 199698a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 19976fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 199898a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 199935136a77SRichard Henderson goto done; 200098a9cb79SRichard Henderson } 200198a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 200235136a77SRichard Henderson goto done; 200335136a77SRichard Henderson case CR_IT: /* Interval Timer */ 200435136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 200535136a77SRichard Henderson nullify_over(ctx); 200698a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2007dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 200849c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 200931234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 201049c29d6cSRichard Henderson } else { 201149c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 201249c29d6cSRichard Henderson } 201398a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 201431234768SRichard Henderson return nullify_end(ctx); 201598a9cb79SRichard Henderson case 26: 201698a9cb79SRichard Henderson case 27: 201798a9cb79SRichard Henderson break; 201898a9cb79SRichard Henderson default: 201998a9cb79SRichard Henderson /* All other control registers are privileged. */ 202035136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 202135136a77SRichard Henderson break; 202298a9cb79SRichard Henderson } 202398a9cb79SRichard Henderson 2024aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20256fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 202635136a77SRichard Henderson save_gpr(ctx, rt, tmp); 202735136a77SRichard Henderson 202835136a77SRichard Henderson done: 202998a9cb79SRichard Henderson cond_free(&ctx->null_cond); 203031234768SRichard Henderson return true; 203198a9cb79SRichard Henderson } 203298a9cb79SRichard Henderson 2033c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 203433423472SRichard Henderson { 2035c603e14aSRichard Henderson unsigned rr = a->r; 2036c603e14aSRichard Henderson unsigned rs = a->sp; 2037967662cdSRichard Henderson TCGv_i64 tmp; 203833423472SRichard Henderson 203933423472SRichard Henderson if (rs >= 5) { 204033423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 204133423472SRichard Henderson } 204233423472SRichard Henderson nullify_over(ctx); 204333423472SRichard Henderson 2044967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2045967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 204633423472SRichard Henderson 204733423472SRichard Henderson if (rs >= 4) { 2048967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2049494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 205033423472SRichard Henderson } else { 2051967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 205233423472SRichard Henderson } 205333423472SRichard Henderson 205431234768SRichard Henderson return nullify_end(ctx); 205533423472SRichard Henderson } 205633423472SRichard Henderson 2057c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 205898a9cb79SRichard Henderson { 2059c603e14aSRichard Henderson unsigned ctl = a->t; 20606fd0c7bcSRichard Henderson TCGv_i64 reg; 20616fd0c7bcSRichard Henderson TCGv_i64 tmp; 206298a9cb79SRichard Henderson 206335136a77SRichard Henderson if (ctl == CR_SAR) { 20644845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2065aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20666fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 206798a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 206898a9cb79SRichard Henderson 206998a9cb79SRichard Henderson cond_free(&ctx->null_cond); 207031234768SRichard Henderson return true; 207198a9cb79SRichard Henderson } 207298a9cb79SRichard Henderson 207335136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 207435136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 207535136a77SRichard Henderson 2076c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 207735136a77SRichard Henderson nullify_over(ctx); 20784c34bab0SHelge Deller 20794c34bab0SHelge Deller if (ctx->is_pa20) { 20804845f015SSven Schnelle reg = load_gpr(ctx, a->r); 20814c34bab0SHelge Deller } else { 20824c34bab0SHelge Deller reg = tcg_temp_new_i64(); 20834c34bab0SHelge Deller tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 20844c34bab0SHelge Deller } 20854845f015SSven Schnelle 208635136a77SRichard Henderson switch (ctl) { 208735136a77SRichard Henderson case CR_IT: 2088ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 208935136a77SRichard Henderson break; 20904f5f2548SRichard Henderson case CR_EIRR: 2091ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 20924f5f2548SRichard Henderson break; 20934f5f2548SRichard Henderson case CR_EIEM: 2094ad75a51eSRichard Henderson gen_helper_write_eiem(tcg_env, reg); 209531234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 20964f5f2548SRichard Henderson break; 20974f5f2548SRichard Henderson 209835136a77SRichard Henderson case CR_IIASQ: 209935136a77SRichard Henderson case CR_IIAOQ: 210035136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 210135136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2102aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21036fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 210435136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 21056fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 21066fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 210735136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 210835136a77SRichard Henderson break; 210935136a77SRichard Henderson 2110d5de20bdSSven Schnelle case CR_PID1: 2111d5de20bdSSven Schnelle case CR_PID2: 2112d5de20bdSSven Schnelle case CR_PID3: 2113d5de20bdSSven Schnelle case CR_PID4: 21146fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2115d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2116ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2117d5de20bdSSven Schnelle #endif 2118d5de20bdSSven Schnelle break; 2119d5de20bdSSven Schnelle 212035136a77SRichard Henderson default: 21216fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 212235136a77SRichard Henderson break; 212335136a77SRichard Henderson } 212431234768SRichard Henderson return nullify_end(ctx); 21254f5f2548SRichard Henderson #endif 212635136a77SRichard Henderson } 212735136a77SRichard Henderson 2128c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 212998a9cb79SRichard Henderson { 2130aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 213198a9cb79SRichard Henderson 21326fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 21336fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 213498a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 213598a9cb79SRichard Henderson 213698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 213731234768SRichard Henderson return true; 213898a9cb79SRichard Henderson } 213998a9cb79SRichard Henderson 2140e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 214198a9cb79SRichard Henderson { 21426fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 214398a9cb79SRichard Henderson 21442330504cSHelge Deller #ifdef CONFIG_USER_ONLY 21452330504cSHelge Deller /* We don't implement space registers in user mode. */ 21466fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 21472330504cSHelge Deller #else 2148967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2149967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 21502330504cSHelge Deller #endif 2151e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 215298a9cb79SRichard Henderson 215398a9cb79SRichard Henderson cond_free(&ctx->null_cond); 215431234768SRichard Henderson return true; 215598a9cb79SRichard Henderson } 215698a9cb79SRichard Henderson 2157e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2158e36f27efSRichard Henderson { 21597b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY 2160e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 21617b2d70a1SHelge Deller #else 21626fd0c7bcSRichard Henderson TCGv_i64 tmp; 2163e1b5a5edSRichard Henderson 21647b2d70a1SHelge Deller /* HP-UX 11i and HP ODE use rsm for read-access to PSW */ 21657b2d70a1SHelge Deller if (a->i) { 21667b2d70a1SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 21677b2d70a1SHelge Deller } 21687b2d70a1SHelge Deller 2169e1b5a5edSRichard Henderson nullify_over(ctx); 2170e1b5a5edSRichard Henderson 2171aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21726fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21736fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2174ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2175e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2176e1b5a5edSRichard Henderson 2177e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 217831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 217931234768SRichard Henderson return nullify_end(ctx); 2180e36f27efSRichard Henderson #endif 2181e1b5a5edSRichard Henderson } 2182e1b5a5edSRichard Henderson 2183e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2184e1b5a5edSRichard Henderson { 2185e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2186e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 21876fd0c7bcSRichard Henderson TCGv_i64 tmp; 2188e1b5a5edSRichard Henderson 2189e1b5a5edSRichard Henderson nullify_over(ctx); 2190e1b5a5edSRichard Henderson 2191aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21926fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21936fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2194ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2195e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2196e1b5a5edSRichard Henderson 2197e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 219831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 219931234768SRichard Henderson return nullify_end(ctx); 2200e36f27efSRichard Henderson #endif 2201e1b5a5edSRichard Henderson } 2202e1b5a5edSRichard Henderson 2203c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2204e1b5a5edSRichard Henderson { 2205e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2206c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 22076fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2208e1b5a5edSRichard Henderson nullify_over(ctx); 2209e1b5a5edSRichard Henderson 2210c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2211aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2212ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2213e1b5a5edSRichard Henderson 2214e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 221531234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 221631234768SRichard Henderson return nullify_end(ctx); 2217c603e14aSRichard Henderson #endif 2218e1b5a5edSRichard Henderson } 2219f49b3537SRichard Henderson 2220e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2221f49b3537SRichard Henderson { 2222f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2223e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2224f49b3537SRichard Henderson nullify_over(ctx); 2225f49b3537SRichard Henderson 2226e36f27efSRichard Henderson if (rfi_r) { 2227ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2228f49b3537SRichard Henderson } else { 2229ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2230f49b3537SRichard Henderson } 223131234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 223207ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 223331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2234f49b3537SRichard Henderson 223531234768SRichard Henderson return nullify_end(ctx); 2236e36f27efSRichard Henderson #endif 2237f49b3537SRichard Henderson } 22386210db05SHelge Deller 2239e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2240e36f27efSRichard Henderson { 2241e36f27efSRichard Henderson return do_rfi(ctx, false); 2242e36f27efSRichard Henderson } 2243e36f27efSRichard Henderson 2244e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2245e36f27efSRichard Henderson { 2246e36f27efSRichard Henderson return do_rfi(ctx, true); 2247e36f27efSRichard Henderson } 2248e36f27efSRichard Henderson 224996927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 22506210db05SHelge Deller { 22516210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 225296927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 22536210db05SHelge Deller nullify_over(ctx); 2254ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 225531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 225631234768SRichard Henderson return nullify_end(ctx); 225796927adbSRichard Henderson #endif 22586210db05SHelge Deller } 225996927adbSRichard Henderson 226096927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 226196927adbSRichard Henderson { 226296927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 226396927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 226496927adbSRichard Henderson nullify_over(ctx); 2265ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 226696927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 226796927adbSRichard Henderson return nullify_end(ctx); 226896927adbSRichard Henderson #endif 226996927adbSRichard Henderson } 2270e1b5a5edSRichard Henderson 22714a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 22724a4554c6SHelge Deller { 22734a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22744a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY 22754a4554c6SHelge Deller nullify_over(ctx); 2276ad75a51eSRichard Henderson gen_helper_getshadowregs(tcg_env); 22774a4554c6SHelge Deller return nullify_end(ctx); 22784a4554c6SHelge Deller #endif 22794a4554c6SHelge Deller } 22804a4554c6SHelge Deller 2281deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 228298a9cb79SRichard Henderson { 2283deee69a1SRichard Henderson if (a->m) { 22846fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 22856fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 22866fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 228798a9cb79SRichard Henderson 228898a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 22896fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2290deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2291deee69a1SRichard Henderson } 229298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 229331234768SRichard Henderson return true; 229498a9cb79SRichard Henderson } 229598a9cb79SRichard Henderson 2296deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 229798a9cb79SRichard Henderson { 22986fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2299eed14219SRichard Henderson TCGv_i32 level, want; 23006fd0c7bcSRichard Henderson TCGv_i64 addr; 230198a9cb79SRichard Henderson 230298a9cb79SRichard Henderson nullify_over(ctx); 230398a9cb79SRichard Henderson 2304deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2305deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2306eed14219SRichard Henderson 2307deee69a1SRichard Henderson if (a->imm) { 2308e5d487c9SRichard Henderson level = tcg_constant_i32(a->ri & 3); 230998a9cb79SRichard Henderson } else { 2310eed14219SRichard Henderson level = tcg_temp_new_i32(); 23116fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2312eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 231398a9cb79SRichard Henderson } 231429dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2315eed14219SRichard Henderson 2316ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2317eed14219SRichard Henderson 2318deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 231931234768SRichard Henderson return nullify_end(ctx); 232098a9cb79SRichard Henderson } 232198a9cb79SRichard Henderson 2322deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 23238d6ae7fbSRichard Henderson { 23248577f354SRichard Henderson if (ctx->is_pa20) { 23258577f354SRichard Henderson return false; 23268577f354SRichard Henderson } 2327deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2328deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23296fd0c7bcSRichard Henderson TCGv_i64 addr; 23306fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 23318d6ae7fbSRichard Henderson 23328d6ae7fbSRichard Henderson nullify_over(ctx); 23338d6ae7fbSRichard Henderson 2334deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2335deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2336deee69a1SRichard Henderson if (a->addr) { 23378577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 23388d6ae7fbSRichard Henderson } else { 23398577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 23408d6ae7fbSRichard Henderson } 23418d6ae7fbSRichard Henderson 234232dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 234332dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 234431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 234531234768SRichard Henderson } 234631234768SRichard Henderson return nullify_end(ctx); 2347deee69a1SRichard Henderson #endif 23488d6ae7fbSRichard Henderson } 234963300a00SRichard Henderson 2350eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 235163300a00SRichard Henderson { 2352deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2353deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23546fd0c7bcSRichard Henderson TCGv_i64 addr; 23556fd0c7bcSRichard Henderson TCGv_i64 ofs; 235663300a00SRichard Henderson 235763300a00SRichard Henderson nullify_over(ctx); 235863300a00SRichard Henderson 2359deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2360eb25d10fSHelge Deller 2361eb25d10fSHelge Deller /* 2362eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2363eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2364eb25d10fSHelge Deller */ 2365eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2366eb25d10fSHelge Deller if (ctx->is_pa20) { 2367eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 236863300a00SRichard Henderson } 2369eb25d10fSHelge Deller 2370eb25d10fSHelge Deller if (local) { 2371eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 237263300a00SRichard Henderson } else { 2373ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 237463300a00SRichard Henderson } 237563300a00SRichard Henderson 2376eb25d10fSHelge Deller if (a->m) { 2377eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2378eb25d10fSHelge Deller } 2379eb25d10fSHelge Deller 2380eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2381eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2382eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2383eb25d10fSHelge Deller } 2384eb25d10fSHelge Deller return nullify_end(ctx); 2385eb25d10fSHelge Deller #endif 2386eb25d10fSHelge Deller } 2387eb25d10fSHelge Deller 2388eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2389eb25d10fSHelge Deller { 2390eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2391eb25d10fSHelge Deller } 2392eb25d10fSHelge Deller 2393eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2394eb25d10fSHelge Deller { 2395eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2396eb25d10fSHelge Deller } 2397eb25d10fSHelge Deller 2398eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2399eb25d10fSHelge Deller { 2400eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2401eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2402eb25d10fSHelge Deller nullify_over(ctx); 2403eb25d10fSHelge Deller 2404eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2405eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2406eb25d10fSHelge Deller 240763300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 240832dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 240931234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 241031234768SRichard Henderson } 241131234768SRichard Henderson return nullify_end(ctx); 2412deee69a1SRichard Henderson #endif 241363300a00SRichard Henderson } 24142dfcca9fSRichard Henderson 24156797c315SNick Hudson /* 24166797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 24176797c315SNick Hudson * See 24186797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 24196797c315SNick Hudson * page 13-9 (195/206) 24206797c315SNick Hudson */ 24216797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 24226797c315SNick Hudson { 24238577f354SRichard Henderson if (ctx->is_pa20) { 24248577f354SRichard Henderson return false; 24258577f354SRichard Henderson } 24266797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24276797c315SNick Hudson #ifndef CONFIG_USER_ONLY 24286fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 24296fd0c7bcSRichard Henderson TCGv_i64 reg; 24306797c315SNick Hudson 24316797c315SNick Hudson nullify_over(ctx); 24326797c315SNick Hudson 24336797c315SNick Hudson /* 24346797c315SNick Hudson * FIXME: 24356797c315SNick Hudson * if (not (pcxl or pcxl2)) 24366797c315SNick Hudson * return gen_illegal(ctx); 24376797c315SNick Hudson */ 24386797c315SNick Hudson 24396fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 24406fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 24416fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 24426797c315SNick Hudson 2443ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 24446797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 24456797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2446ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 24476797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 24486797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 24496797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2450d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 24516797c315SNick Hudson 24526797c315SNick Hudson reg = load_gpr(ctx, a->r); 24536797c315SNick Hudson if (a->addr) { 24548577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 24556797c315SNick Hudson } else { 24568577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 24576797c315SNick Hudson } 24586797c315SNick Hudson 24596797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 24606797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 24616797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24626797c315SNick Hudson } 24636797c315SNick Hudson return nullify_end(ctx); 24646797c315SNick Hudson #endif 24656797c315SNick Hudson } 24666797c315SNick Hudson 24678577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 24688577f354SRichard Henderson { 24698577f354SRichard Henderson if (!ctx->is_pa20) { 24708577f354SRichard Henderson return false; 24718577f354SRichard Henderson } 24728577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24738577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 24748577f354SRichard Henderson nullify_over(ctx); 24758577f354SRichard Henderson { 24768577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 24778577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 24788577f354SRichard Henderson 24798577f354SRichard Henderson if (a->data) { 24808577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 24818577f354SRichard Henderson } else { 24828577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 24838577f354SRichard Henderson } 24848577f354SRichard Henderson } 24858577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 24868577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 24878577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24888577f354SRichard Henderson } 24898577f354SRichard Henderson return nullify_end(ctx); 24908577f354SRichard Henderson #endif 24918577f354SRichard Henderson } 24928577f354SRichard Henderson 2493deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 24942dfcca9fSRichard Henderson { 2495deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2496deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24976fd0c7bcSRichard Henderson TCGv_i64 vaddr; 24986fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 24992dfcca9fSRichard Henderson 25002dfcca9fSRichard Henderson nullify_over(ctx); 25012dfcca9fSRichard Henderson 2502deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 25032dfcca9fSRichard Henderson 2504aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2505ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 25062dfcca9fSRichard Henderson 25072dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2508deee69a1SRichard Henderson if (a->m) { 2509deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 25102dfcca9fSRichard Henderson } 2511deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 25122dfcca9fSRichard Henderson 251331234768SRichard Henderson return nullify_end(ctx); 2514deee69a1SRichard Henderson #endif 25152dfcca9fSRichard Henderson } 251643a97b81SRichard Henderson 2517deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 251843a97b81SRichard Henderson { 251943a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 252043a97b81SRichard Henderson 252143a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 252243a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 252343a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 252443a97b81SRichard Henderson since the entire address space is coherent. */ 2525a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 252643a97b81SRichard Henderson 252731234768SRichard Henderson cond_free(&ctx->null_cond); 252831234768SRichard Henderson return true; 252943a97b81SRichard Henderson } 253098a9cb79SRichard Henderson 2531faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2532b2167459SRichard Henderson { 25330c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2534b2167459SRichard Henderson } 2535b2167459SRichard Henderson 2536faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2537b2167459SRichard Henderson { 25380c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2539b2167459SRichard Henderson } 2540b2167459SRichard Henderson 2541faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2542b2167459SRichard Henderson { 25430c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2544b2167459SRichard Henderson } 2545b2167459SRichard Henderson 2546faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2547b2167459SRichard Henderson { 25480c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 25490c982a28SRichard Henderson } 2550b2167459SRichard Henderson 2551faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 25520c982a28SRichard Henderson { 25530c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 25540c982a28SRichard Henderson } 25550c982a28SRichard Henderson 255663c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 25570c982a28SRichard Henderson { 25580c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 25590c982a28SRichard Henderson } 25600c982a28SRichard Henderson 256163c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25620c982a28SRichard Henderson { 25630c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 25640c982a28SRichard Henderson } 25650c982a28SRichard Henderson 256663c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25670c982a28SRichard Henderson { 25680c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 25690c982a28SRichard Henderson } 25700c982a28SRichard Henderson 257163c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25720c982a28SRichard Henderson { 25730c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 25740c982a28SRichard Henderson } 25750c982a28SRichard Henderson 257663c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 25770c982a28SRichard Henderson { 25780c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 25790c982a28SRichard Henderson } 25800c982a28SRichard Henderson 258163c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25820c982a28SRichard Henderson { 25830c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 25840c982a28SRichard Henderson } 25850c982a28SRichard Henderson 2586fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 25870c982a28SRichard Henderson { 25886fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 25890c982a28SRichard Henderson } 25900c982a28SRichard Henderson 2591fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 25920c982a28SRichard Henderson { 25936fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 25940c982a28SRichard Henderson } 25950c982a28SRichard Henderson 2596fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 25970c982a28SRichard Henderson { 25980c982a28SRichard Henderson if (a->cf == 0) { 25990c982a28SRichard Henderson unsigned r2 = a->r2; 26000c982a28SRichard Henderson unsigned r1 = a->r1; 26010c982a28SRichard Henderson unsigned rt = a->t; 26020c982a28SRichard Henderson 26037aee8189SRichard Henderson if (rt == 0) { /* NOP */ 26047aee8189SRichard Henderson cond_free(&ctx->null_cond); 26057aee8189SRichard Henderson return true; 26067aee8189SRichard Henderson } 26077aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2608b2167459SRichard Henderson if (r1 == 0) { 26096fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 26106fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2611b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2612b2167459SRichard Henderson } else { 2613b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2614b2167459SRichard Henderson } 2615b2167459SRichard Henderson cond_free(&ctx->null_cond); 261631234768SRichard Henderson return true; 2617b2167459SRichard Henderson } 26187aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 26197aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 26207aee8189SRichard Henderson * 26217aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 26227aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 26237aee8189SRichard Henderson * currently implemented as idle. 26247aee8189SRichard Henderson */ 26257aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 26267aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 26277aee8189SRichard Henderson until the next timer interrupt. */ 26287aee8189SRichard Henderson nullify_over(ctx); 26297aee8189SRichard Henderson 26307aee8189SRichard Henderson /* Advance the instruction queue. */ 2631741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 2632741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 26337aee8189SRichard Henderson nullify_set(ctx, 0); 26347aee8189SRichard Henderson 26357aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2636ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 263729dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 26387aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 26397aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 26407aee8189SRichard Henderson 26417aee8189SRichard Henderson return nullify_end(ctx); 26427aee8189SRichard Henderson } 26437aee8189SRichard Henderson #endif 26447aee8189SRichard Henderson } 26456fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 26467aee8189SRichard Henderson } 2647b2167459SRichard Henderson 2648fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2649b2167459SRichard Henderson { 26506fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 26510c982a28SRichard Henderson } 26520c982a28SRichard Henderson 2653345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 26540c982a28SRichard Henderson { 26556fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2656b2167459SRichard Henderson 26570c982a28SRichard Henderson if (a->cf) { 2658b2167459SRichard Henderson nullify_over(ctx); 2659b2167459SRichard Henderson } 26600c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26610c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2662345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 266331234768SRichard Henderson return nullify_end(ctx); 2664b2167459SRichard Henderson } 2665b2167459SRichard Henderson 2666af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2667b2167459SRichard Henderson { 26686fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2669b2167459SRichard Henderson 26700c982a28SRichard Henderson if (a->cf) { 2671b2167459SRichard Henderson nullify_over(ctx); 2672b2167459SRichard Henderson } 26730c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26740c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 26756fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64); 267631234768SRichard Henderson return nullify_end(ctx); 2677b2167459SRichard Henderson } 2678b2167459SRichard Henderson 2679af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2680b2167459SRichard Henderson { 26816fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2682b2167459SRichard Henderson 26830c982a28SRichard Henderson if (a->cf) { 2684b2167459SRichard Henderson nullify_over(ctx); 2685b2167459SRichard Henderson } 26860c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26870c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2688aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 26896fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 26906fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64); 269131234768SRichard Henderson return nullify_end(ctx); 2692b2167459SRichard Henderson } 2693b2167459SRichard Henderson 2694af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2695b2167459SRichard Henderson { 26960c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 26970c982a28SRichard Henderson } 26980c982a28SRichard Henderson 2699af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 27000c982a28SRichard Henderson { 27010c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 27020c982a28SRichard Henderson } 27030c982a28SRichard Henderson 2704af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 27050c982a28SRichard Henderson { 27066fd0c7bcSRichard Henderson TCGv_i64 tmp; 2707b2167459SRichard Henderson 2708b2167459SRichard Henderson nullify_over(ctx); 2709b2167459SRichard Henderson 2710aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 27116fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, cpu_psw_cb, 3); 2712b2167459SRichard Henderson if (!is_i) { 27136fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2714b2167459SRichard Henderson } 27156fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 27166fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 2717af240753SRichard Henderson do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false, 27186fd0c7bcSRichard Henderson is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64); 271931234768SRichard Henderson return nullify_end(ctx); 2720b2167459SRichard Henderson } 2721b2167459SRichard Henderson 2722af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2723b2167459SRichard Henderson { 27240c982a28SRichard Henderson return do_dcor(ctx, a, false); 27250c982a28SRichard Henderson } 27260c982a28SRichard Henderson 2727af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 27280c982a28SRichard Henderson { 27290c982a28SRichard Henderson return do_dcor(ctx, a, true); 27300c982a28SRichard Henderson } 27310c982a28SRichard Henderson 27320c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 27330c982a28SRichard Henderson { 2734a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 27356fd0c7bcSRichard Henderson TCGv_i64 cout; 2736b2167459SRichard Henderson 2737b2167459SRichard Henderson nullify_over(ctx); 2738b2167459SRichard Henderson 27390c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 27400c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2741b2167459SRichard Henderson 2742aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2743aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2744aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2745aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2746b2167459SRichard Henderson 2747b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 27486fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 27496fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2750b2167459SRichard Henderson 275172ca8753SRichard Henderson /* 275272ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 275372ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 275472ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 275572ca8753SRichard Henderson * proper inputs to the addition without movcond. 275672ca8753SRichard Henderson */ 27576fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 27586fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 27596fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 276072ca8753SRichard Henderson 2761a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2762a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2763a4db4a78SRichard Henderson addc, ctx->zero); 2764b2167459SRichard Henderson 2765b2167459SRichard Henderson /* Write back the result register. */ 27660c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2767b2167459SRichard Henderson 2768b2167459SRichard Henderson /* Write back PSW[CB]. */ 27696fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 27706fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2771b2167459SRichard Henderson 2772b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 277372ca8753SRichard Henderson cout = get_psw_carry(ctx, false); 27746fd0c7bcSRichard Henderson tcg_gen_neg_i64(cpu_psw_v, cout); 27756fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2776b2167459SRichard Henderson 2777b2167459SRichard Henderson /* Install the new nullification. */ 27780c982a28SRichard Henderson if (a->cf) { 27796fd0c7bcSRichard Henderson TCGv_i64 sv = NULL; 2780b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2781b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 2782b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 2783b2167459SRichard Henderson } 2784a751eb31SRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv); 2785b2167459SRichard Henderson } 2786b2167459SRichard Henderson 278731234768SRichard Henderson return nullify_end(ctx); 2788b2167459SRichard Henderson } 2789b2167459SRichard Henderson 27900588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2791b2167459SRichard Henderson { 27920588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 27930588e061SRichard Henderson } 27940588e061SRichard Henderson 27950588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 27960588e061SRichard Henderson { 27970588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 27980588e061SRichard Henderson } 27990588e061SRichard Henderson 28000588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 28010588e061SRichard Henderson { 28020588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 28030588e061SRichard Henderson } 28040588e061SRichard Henderson 28050588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 28060588e061SRichard Henderson { 28070588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 28080588e061SRichard Henderson } 28090588e061SRichard Henderson 28100588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 28110588e061SRichard Henderson { 28120588e061SRichard Henderson return do_sub_imm(ctx, a, false); 28130588e061SRichard Henderson } 28140588e061SRichard Henderson 28150588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 28160588e061SRichard Henderson { 28170588e061SRichard Henderson return do_sub_imm(ctx, a, true); 28180588e061SRichard Henderson } 28190588e061SRichard Henderson 2820345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 28210588e061SRichard Henderson { 28226fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 2823b2167459SRichard Henderson 28240588e061SRichard Henderson if (a->cf) { 2825b2167459SRichard Henderson nullify_over(ctx); 2826b2167459SRichard Henderson } 2827b2167459SRichard Henderson 28286fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 28290588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 2830345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2831b2167459SRichard Henderson 283231234768SRichard Henderson return nullify_end(ctx); 2833b2167459SRichard Henderson } 2834b2167459SRichard Henderson 28350843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 28360843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 28370843563fSRichard Henderson { 28380843563fSRichard Henderson TCGv_i64 r1, r2, dest; 28390843563fSRichard Henderson 28400843563fSRichard Henderson if (!ctx->is_pa20) { 28410843563fSRichard Henderson return false; 28420843563fSRichard Henderson } 28430843563fSRichard Henderson 28440843563fSRichard Henderson nullify_over(ctx); 28450843563fSRichard Henderson 28460843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 28470843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 28480843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 28490843563fSRichard Henderson 28500843563fSRichard Henderson fn(dest, r1, r2); 28510843563fSRichard Henderson save_gpr(ctx, a->t, dest); 28520843563fSRichard Henderson 28530843563fSRichard Henderson return nullify_end(ctx); 28540843563fSRichard Henderson } 28550843563fSRichard Henderson 2856151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 2857151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 2858151f309bSRichard Henderson { 2859151f309bSRichard Henderson TCGv_i64 r, dest; 2860151f309bSRichard Henderson 2861151f309bSRichard Henderson if (!ctx->is_pa20) { 2862151f309bSRichard Henderson return false; 2863151f309bSRichard Henderson } 2864151f309bSRichard Henderson 2865151f309bSRichard Henderson nullify_over(ctx); 2866151f309bSRichard Henderson 2867151f309bSRichard Henderson r = load_gpr(ctx, a->r); 2868151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 2869151f309bSRichard Henderson 2870151f309bSRichard Henderson fn(dest, r, a->i); 2871151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 2872151f309bSRichard Henderson 2873151f309bSRichard Henderson return nullify_end(ctx); 2874151f309bSRichard Henderson } 2875151f309bSRichard Henderson 28763bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 28773bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 28783bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 28793bbb8e48SRichard Henderson { 28803bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 28813bbb8e48SRichard Henderson 28823bbb8e48SRichard Henderson if (!ctx->is_pa20) { 28833bbb8e48SRichard Henderson return false; 28843bbb8e48SRichard Henderson } 28853bbb8e48SRichard Henderson 28863bbb8e48SRichard Henderson nullify_over(ctx); 28873bbb8e48SRichard Henderson 28883bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 28893bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 28903bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 28913bbb8e48SRichard Henderson 28923bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 28933bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 28943bbb8e48SRichard Henderson 28953bbb8e48SRichard Henderson return nullify_end(ctx); 28963bbb8e48SRichard Henderson } 28973bbb8e48SRichard Henderson 28980843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 28990843563fSRichard Henderson { 29000843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 29010843563fSRichard Henderson } 29020843563fSRichard Henderson 29030843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 29040843563fSRichard Henderson { 29050843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 29060843563fSRichard Henderson } 29070843563fSRichard Henderson 29080843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 29090843563fSRichard Henderson { 29100843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 29110843563fSRichard Henderson } 29120843563fSRichard Henderson 29131b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 29141b3cb7c8SRichard Henderson { 29151b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 29161b3cb7c8SRichard Henderson } 29171b3cb7c8SRichard Henderson 2918151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 2919151f309bSRichard Henderson { 2920151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 2921151f309bSRichard Henderson } 2922151f309bSRichard Henderson 2923151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 2924151f309bSRichard Henderson { 2925151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 2926151f309bSRichard Henderson } 2927151f309bSRichard Henderson 2928151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 2929151f309bSRichard Henderson { 2930151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 2931151f309bSRichard Henderson } 2932151f309bSRichard Henderson 29333bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 29343bbb8e48SRichard Henderson { 29353bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 29363bbb8e48SRichard Henderson } 29373bbb8e48SRichard Henderson 29383bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 29393bbb8e48SRichard Henderson { 29403bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 29413bbb8e48SRichard Henderson } 29423bbb8e48SRichard Henderson 294310c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 294410c9e58dSRichard Henderson { 294510c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 294610c9e58dSRichard Henderson } 294710c9e58dSRichard Henderson 294810c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 294910c9e58dSRichard Henderson { 295010c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 295110c9e58dSRichard Henderson } 295210c9e58dSRichard Henderson 295310c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 295410c9e58dSRichard Henderson { 295510c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 295610c9e58dSRichard Henderson } 295710c9e58dSRichard Henderson 2958c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2959c2a7ee3fSRichard Henderson { 2960c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 2961c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2962c2a7ee3fSRichard Henderson 2963c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 2964c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 2965c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 2966c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2967c2a7ee3fSRichard Henderson } 2968c2a7ee3fSRichard Henderson 2969c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 2970c2a7ee3fSRichard Henderson { 2971c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 2972c2a7ee3fSRichard Henderson } 2973c2a7ee3fSRichard Henderson 2974c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2975c2a7ee3fSRichard Henderson { 2976c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 2977c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2978c2a7ee3fSRichard Henderson 2979c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 2980c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 2981c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 2982c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2983c2a7ee3fSRichard Henderson } 2984c2a7ee3fSRichard Henderson 2985c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 2986c2a7ee3fSRichard Henderson { 2987c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 2988c2a7ee3fSRichard Henderson } 2989c2a7ee3fSRichard Henderson 2990c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2991c2a7ee3fSRichard Henderson { 2992c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2993c2a7ee3fSRichard Henderson 2994c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 2995c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 2996c2a7ee3fSRichard Henderson } 2997c2a7ee3fSRichard Henderson 2998c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 2999c2a7ee3fSRichard Henderson { 3000c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 3001c2a7ee3fSRichard Henderson } 3002c2a7ee3fSRichard Henderson 3003c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3004c2a7ee3fSRichard Henderson { 3005c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 3006c2a7ee3fSRichard Henderson } 3007c2a7ee3fSRichard Henderson 3008c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 3009c2a7ee3fSRichard Henderson { 3010c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 3011c2a7ee3fSRichard Henderson } 3012c2a7ee3fSRichard Henderson 30134e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 30144e7abdb1SRichard Henderson { 30154e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 30164e7abdb1SRichard Henderson 30174e7abdb1SRichard Henderson if (!ctx->is_pa20) { 30184e7abdb1SRichard Henderson return false; 30194e7abdb1SRichard Henderson } 30204e7abdb1SRichard Henderson 30214e7abdb1SRichard Henderson nullify_over(ctx); 30224e7abdb1SRichard Henderson 30234e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 30244e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 30254e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 30264e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 30274e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 30284e7abdb1SRichard Henderson 30294e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 30304e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 30314e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 30324e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 30334e7abdb1SRichard Henderson 30344e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 30354e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 30364e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 30374e7abdb1SRichard Henderson 30384e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 30394e7abdb1SRichard Henderson return nullify_end(ctx); 30404e7abdb1SRichard Henderson } 30414e7abdb1SRichard Henderson 30421cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 304396d6407fSRichard Henderson { 3044b5caa17cSRichard Henderson if (ctx->is_pa20) { 3045b5caa17cSRichard Henderson /* 3046b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3047b5caa17cSRichard Henderson * Any base modification still occurs. 3048b5caa17cSRichard Henderson */ 3049b5caa17cSRichard Henderson if (a->t == 0) { 3050b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3051b5caa17cSRichard Henderson } 3052b5caa17cSRichard Henderson } else if (a->size > MO_32) { 30530786a3b6SHelge Deller return gen_illegal(ctx); 3054c53e401eSRichard Henderson } 30551cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 30561cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 305796d6407fSRichard Henderson } 305896d6407fSRichard Henderson 30591cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 306096d6407fSRichard Henderson { 30611cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3062c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 30630786a3b6SHelge Deller return gen_illegal(ctx); 306496d6407fSRichard Henderson } 3065c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 30660786a3b6SHelge Deller } 306796d6407fSRichard Henderson 30681cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 306996d6407fSRichard Henderson { 3070b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3071a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 30726fd0c7bcSRichard Henderson TCGv_i64 addr; 307396d6407fSRichard Henderson 3074c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 307551416c4eSRichard Henderson return gen_illegal(ctx); 307651416c4eSRichard Henderson } 307751416c4eSRichard Henderson 307896d6407fSRichard Henderson nullify_over(ctx); 307996d6407fSRichard Henderson 30801cd012a5SRichard Henderson if (a->m) { 308186f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 308286f8d05fSRichard Henderson we see the result of the load. */ 3083aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 308496d6407fSRichard Henderson } else { 30851cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 308696d6407fSRichard Henderson } 308796d6407fSRichard Henderson 30881cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0, 308917fe594cSRichard Henderson a->disp, a->sp, a->m, MMU_DISABLED(ctx)); 3090b1af755cSRichard Henderson 3091b1af755cSRichard Henderson /* 3092b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3093b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3094b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3095b1af755cSRichard Henderson * 3096b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3097b1af755cSRichard Henderson * with the ,co completer. 3098b1af755cSRichard Henderson */ 3099b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3100b1af755cSRichard Henderson 3101a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3102b1af755cSRichard Henderson 31031cd012a5SRichard Henderson if (a->m) { 31041cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 310596d6407fSRichard Henderson } 31061cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 310796d6407fSRichard Henderson 310831234768SRichard Henderson return nullify_end(ctx); 310996d6407fSRichard Henderson } 311096d6407fSRichard Henderson 31111cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 311296d6407fSRichard Henderson { 31136fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31146fd0c7bcSRichard Henderson TCGv_i64 addr; 311596d6407fSRichard Henderson 311696d6407fSRichard Henderson nullify_over(ctx); 311796d6407fSRichard Henderson 31181cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 311917fe594cSRichard Henderson MMU_DISABLED(ctx)); 31201cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 31211cd012a5SRichard Henderson if (a->a) { 3122f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3123ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3124f9f46db4SEmilio G. Cota } else { 3125ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3126f9f46db4SEmilio G. Cota } 3127f9f46db4SEmilio G. Cota } else { 3128f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3129ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 313096d6407fSRichard Henderson } else { 3131ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 313296d6407fSRichard Henderson } 3133f9f46db4SEmilio G. Cota } 31341cd012a5SRichard Henderson if (a->m) { 31356fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 31361cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 313796d6407fSRichard Henderson } 313896d6407fSRichard Henderson 313931234768SRichard Henderson return nullify_end(ctx); 314096d6407fSRichard Henderson } 314196d6407fSRichard Henderson 314225460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 314325460fc5SRichard Henderson { 31446fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31456fd0c7bcSRichard Henderson TCGv_i64 addr; 314625460fc5SRichard Henderson 314725460fc5SRichard Henderson if (!ctx->is_pa20) { 314825460fc5SRichard Henderson return false; 314925460fc5SRichard Henderson } 315025460fc5SRichard Henderson nullify_over(ctx); 315125460fc5SRichard Henderson 315225460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 315317fe594cSRichard Henderson MMU_DISABLED(ctx)); 315425460fc5SRichard Henderson val = load_gpr(ctx, a->r); 315525460fc5SRichard Henderson if (a->a) { 315625460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 315725460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 315825460fc5SRichard Henderson } else { 315925460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 316025460fc5SRichard Henderson } 316125460fc5SRichard Henderson } else { 316225460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 316325460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 316425460fc5SRichard Henderson } else { 316525460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 316625460fc5SRichard Henderson } 316725460fc5SRichard Henderson } 316825460fc5SRichard Henderson if (a->m) { 31696fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 317025460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 317125460fc5SRichard Henderson } 317225460fc5SRichard Henderson 317325460fc5SRichard Henderson return nullify_end(ctx); 317425460fc5SRichard Henderson } 317525460fc5SRichard Henderson 31761cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3177d0a851ccSRichard Henderson { 3178d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3179d0a851ccSRichard Henderson 3180d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3181451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 31821cd012a5SRichard Henderson trans_ld(ctx, a); 3183d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 318431234768SRichard Henderson return true; 3185d0a851ccSRichard Henderson } 3186d0a851ccSRichard Henderson 31871cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3188d0a851ccSRichard Henderson { 3189d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3190d0a851ccSRichard Henderson 3191d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3192451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 31931cd012a5SRichard Henderson trans_st(ctx, a); 3194d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 319531234768SRichard Henderson return true; 3196d0a851ccSRichard Henderson } 319795412a61SRichard Henderson 31980588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3199b2167459SRichard Henderson { 32006fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3201b2167459SRichard Henderson 32026fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 32030588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3204b2167459SRichard Henderson cond_free(&ctx->null_cond); 320531234768SRichard Henderson return true; 3206b2167459SRichard Henderson } 3207b2167459SRichard Henderson 32080588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3209b2167459SRichard Henderson { 32106fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 32116fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3212b2167459SRichard Henderson 32136fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3214b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3215b2167459SRichard Henderson cond_free(&ctx->null_cond); 321631234768SRichard Henderson return true; 3217b2167459SRichard Henderson } 3218b2167459SRichard Henderson 32190588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3220b2167459SRichard Henderson { 32216fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3222b2167459SRichard Henderson 3223b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3224d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 32250588e061SRichard Henderson if (a->b == 0) { 32266fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3227b2167459SRichard Henderson } else { 32286fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3229b2167459SRichard Henderson } 32300588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3231b2167459SRichard Henderson cond_free(&ctx->null_cond); 323231234768SRichard Henderson return true; 3233b2167459SRichard Henderson } 3234b2167459SRichard Henderson 32356fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3236e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 323798cd9ca7SRichard Henderson { 32386fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 323998cd9ca7SRichard Henderson DisasCond cond; 324098cd9ca7SRichard Henderson 324198cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3242aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 324398cd9ca7SRichard Henderson 32446fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 324598cd9ca7SRichard Henderson 3246f764718dSRichard Henderson sv = NULL; 3247b47a4a02SSven Schnelle if (cond_need_sv(c)) { 324898cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 324998cd9ca7SRichard Henderson } 325098cd9ca7SRichard Henderson 32514fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 325201afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 325398cd9ca7SRichard Henderson } 325498cd9ca7SRichard Henderson 325501afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 325698cd9ca7SRichard Henderson { 3257e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3258e9efd4bcSRichard Henderson return false; 3259e9efd4bcSRichard Henderson } 326001afb7beSRichard Henderson nullify_over(ctx); 3261e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3262e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 326301afb7beSRichard Henderson } 326401afb7beSRichard Henderson 326501afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 326601afb7beSRichard Henderson { 3267c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3268c65c3ee1SRichard Henderson return false; 3269c65c3ee1SRichard Henderson } 327001afb7beSRichard Henderson nullify_over(ctx); 32716fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3272c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 327301afb7beSRichard Henderson } 327401afb7beSRichard Henderson 32756fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 327601afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 327701afb7beSRichard Henderson { 32786fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 327998cd9ca7SRichard Henderson DisasCond cond; 3280bdcccc17SRichard Henderson bool d = false; 328198cd9ca7SRichard Henderson 3282f25d3160SRichard Henderson /* 3283f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3284f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3285f25d3160SRichard Henderson */ 3286f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3287f25d3160SRichard Henderson d = c >= 5; 3288f25d3160SRichard Henderson if (d) { 3289f25d3160SRichard Henderson c &= 3; 3290f25d3160SRichard Henderson } 3291f25d3160SRichard Henderson } 3292f25d3160SRichard Henderson 329398cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3294aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3295f764718dSRichard Henderson sv = NULL; 3296bdcccc17SRichard Henderson cb_cond = NULL; 329798cd9ca7SRichard Henderson 3298b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3299aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3300aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3301bdcccc17SRichard Henderson 33026fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 33036fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 33046fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 33056fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3306bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3307b47a4a02SSven Schnelle } else { 33086fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3309b47a4a02SSven Schnelle } 3310b47a4a02SSven Schnelle if (cond_need_sv(c)) { 331198cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 331298cd9ca7SRichard Henderson } 331398cd9ca7SRichard Henderson 3314a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 331543675d20SSven Schnelle save_gpr(ctx, r, dest); 331601afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 331798cd9ca7SRichard Henderson } 331898cd9ca7SRichard Henderson 331901afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 332098cd9ca7SRichard Henderson { 332101afb7beSRichard Henderson nullify_over(ctx); 332201afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 332301afb7beSRichard Henderson } 332401afb7beSRichard Henderson 332501afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 332601afb7beSRichard Henderson { 332701afb7beSRichard Henderson nullify_over(ctx); 33286fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 332901afb7beSRichard Henderson } 333001afb7beSRichard Henderson 333101afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 333201afb7beSRichard Henderson { 33336fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 333498cd9ca7SRichard Henderson DisasCond cond; 333598cd9ca7SRichard Henderson 333698cd9ca7SRichard Henderson nullify_over(ctx); 333798cd9ca7SRichard Henderson 3338aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 333901afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 334084e224d4SRichard Henderson if (cond_need_ext(ctx, a->d)) { 33411e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 33426fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 33436fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 33441e9ab9fbSRichard Henderson } else { 33456fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 33461e9ab9fbSRichard Henderson } 334798cd9ca7SRichard Henderson 33481e9ab9fbSRichard Henderson cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 334901afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 335098cd9ca7SRichard Henderson } 335198cd9ca7SRichard Henderson 335201afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 335398cd9ca7SRichard Henderson { 33546fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 335501afb7beSRichard Henderson DisasCond cond; 33561e9ab9fbSRichard Henderson int p; 335701afb7beSRichard Henderson 335801afb7beSRichard Henderson nullify_over(ctx); 335901afb7beSRichard Henderson 3360aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 336101afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 336284e224d4SRichard Henderson p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0); 33636fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, tcg_r, p); 336401afb7beSRichard Henderson 336501afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 336601afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 336701afb7beSRichard Henderson } 336801afb7beSRichard Henderson 336901afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 337001afb7beSRichard Henderson { 33716fd0c7bcSRichard Henderson TCGv_i64 dest; 337298cd9ca7SRichard Henderson DisasCond cond; 337398cd9ca7SRichard Henderson 337498cd9ca7SRichard Henderson nullify_over(ctx); 337598cd9ca7SRichard Henderson 337601afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 337701afb7beSRichard Henderson if (a->r1 == 0) { 33786fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 337998cd9ca7SRichard Henderson } else { 33806fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 338198cd9ca7SRichard Henderson } 338298cd9ca7SRichard Henderson 33834fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 33844fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 338501afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 338601afb7beSRichard Henderson } 338701afb7beSRichard Henderson 338801afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 338901afb7beSRichard Henderson { 33906fd0c7bcSRichard Henderson TCGv_i64 dest; 339101afb7beSRichard Henderson DisasCond cond; 339201afb7beSRichard Henderson 339301afb7beSRichard Henderson nullify_over(ctx); 339401afb7beSRichard Henderson 339501afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 33966fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 339701afb7beSRichard Henderson 33984fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 33994fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 340001afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 340198cd9ca7SRichard Henderson } 340298cd9ca7SRichard Henderson 3403f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 34040b1347d2SRichard Henderson { 34056fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 34060b1347d2SRichard Henderson 3407f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3408f7b775a9SRichard Henderson return false; 3409f7b775a9SRichard Henderson } 341030878590SRichard Henderson if (a->c) { 34110b1347d2SRichard Henderson nullify_over(ctx); 34120b1347d2SRichard Henderson } 34130b1347d2SRichard Henderson 341430878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3415f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 341630878590SRichard Henderson if (a->r1 == 0) { 3417f7b775a9SRichard Henderson if (a->d) { 34186fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3419f7b775a9SRichard Henderson } else { 3420aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3421f7b775a9SRichard Henderson 34226fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 34236fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 34246fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3425f7b775a9SRichard Henderson } 342630878590SRichard Henderson } else if (a->r1 == a->r2) { 3427f7b775a9SRichard Henderson if (a->d) { 34286fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3429f7b775a9SRichard Henderson } else { 34300b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3431e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3432e1d635e8SRichard Henderson 34336fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 34346fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3435f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3436e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 34376fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3438f7b775a9SRichard Henderson } 3439f7b775a9SRichard Henderson } else { 34406fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3441f7b775a9SRichard Henderson 3442f7b775a9SRichard Henderson if (a->d) { 3443aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3444aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3445f7b775a9SRichard Henderson 34466fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 3447a01491a2SHelge Deller tcg_gen_shl_i64(t, src1, n); 34486fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 3449a01491a2SHelge Deller tcg_gen_shr_i64(dest, src2, cpu_sar); 34506fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 34510b1347d2SRichard Henderson } else { 34520b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 34530b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 34540b1347d2SRichard Henderson 34556fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3456967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3457967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 34580b1347d2SRichard Henderson } 3459f7b775a9SRichard Henderson } 346030878590SRichard Henderson save_gpr(ctx, a->t, dest); 34610b1347d2SRichard Henderson 34620b1347d2SRichard Henderson /* Install the new nullification. */ 34630b1347d2SRichard Henderson cond_free(&ctx->null_cond); 346430878590SRichard Henderson if (a->c) { 34654fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 34660b1347d2SRichard Henderson } 346731234768SRichard Henderson return nullify_end(ctx); 34680b1347d2SRichard Henderson } 34690b1347d2SRichard Henderson 3470f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 34710b1347d2SRichard Henderson { 3472f7b775a9SRichard Henderson unsigned width, sa; 34736fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 34740b1347d2SRichard Henderson 3475f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3476f7b775a9SRichard Henderson return false; 3477f7b775a9SRichard Henderson } 347830878590SRichard Henderson if (a->c) { 34790b1347d2SRichard Henderson nullify_over(ctx); 34800b1347d2SRichard Henderson } 34810b1347d2SRichard Henderson 3482f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3483f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3484f7b775a9SRichard Henderson 348530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 348630878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 348705bfd4dbSRichard Henderson if (a->r1 == 0) { 34886fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3489c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 34906fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3491f7b775a9SRichard Henderson } else { 3492f7b775a9SRichard Henderson assert(!a->d); 3493f7b775a9SRichard Henderson if (a->r1 == a->r2) { 34940b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 34956fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 34960b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 34976fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 34980b1347d2SRichard Henderson } else { 3499967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3500967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 35010b1347d2SRichard Henderson } 3502f7b775a9SRichard Henderson } 350330878590SRichard Henderson save_gpr(ctx, a->t, dest); 35040b1347d2SRichard Henderson 35050b1347d2SRichard Henderson /* Install the new nullification. */ 35060b1347d2SRichard Henderson cond_free(&ctx->null_cond); 350730878590SRichard Henderson if (a->c) { 35084fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 35090b1347d2SRichard Henderson } 351031234768SRichard Henderson return nullify_end(ctx); 35110b1347d2SRichard Henderson } 35120b1347d2SRichard Henderson 3513bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 35140b1347d2SRichard Henderson { 3515bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 35166fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 35170b1347d2SRichard Henderson 3518bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3519bd792da3SRichard Henderson return false; 3520bd792da3SRichard Henderson } 352130878590SRichard Henderson if (a->c) { 35220b1347d2SRichard Henderson nullify_over(ctx); 35230b1347d2SRichard Henderson } 35240b1347d2SRichard Henderson 352530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 352630878590SRichard Henderson src = load_gpr(ctx, a->r); 3527aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 35280b1347d2SRichard Henderson 35290b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 35306fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 35316fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3532d781cb77SRichard Henderson 353330878590SRichard Henderson if (a->se) { 3534bd792da3SRichard Henderson if (!a->d) { 35356fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3536bd792da3SRichard Henderson src = dest; 3537bd792da3SRichard Henderson } 35386fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 35396fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 35400b1347d2SRichard Henderson } else { 3541bd792da3SRichard Henderson if (!a->d) { 35426fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3543bd792da3SRichard Henderson src = dest; 3544bd792da3SRichard Henderson } 35456fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 35466fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 35470b1347d2SRichard Henderson } 354830878590SRichard Henderson save_gpr(ctx, a->t, dest); 35490b1347d2SRichard Henderson 35500b1347d2SRichard Henderson /* Install the new nullification. */ 35510b1347d2SRichard Henderson cond_free(&ctx->null_cond); 355230878590SRichard Henderson if (a->c) { 3553bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35540b1347d2SRichard Henderson } 355531234768SRichard Henderson return nullify_end(ctx); 35560b1347d2SRichard Henderson } 35570b1347d2SRichard Henderson 3558bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 35590b1347d2SRichard Henderson { 3560bd792da3SRichard Henderson unsigned len, cpos, width; 35616fd0c7bcSRichard Henderson TCGv_i64 dest, src; 35620b1347d2SRichard Henderson 3563bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3564bd792da3SRichard Henderson return false; 3565bd792da3SRichard Henderson } 356630878590SRichard Henderson if (a->c) { 35670b1347d2SRichard Henderson nullify_over(ctx); 35680b1347d2SRichard Henderson } 35690b1347d2SRichard Henderson 3570bd792da3SRichard Henderson len = a->len; 3571bd792da3SRichard Henderson width = a->d ? 64 : 32; 3572bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3573bd792da3SRichard Henderson if (cpos + len > width) { 3574bd792da3SRichard Henderson len = width - cpos; 3575bd792da3SRichard Henderson } 3576bd792da3SRichard Henderson 357730878590SRichard Henderson dest = dest_gpr(ctx, a->t); 357830878590SRichard Henderson src = load_gpr(ctx, a->r); 357930878590SRichard Henderson if (a->se) { 35806fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 35810b1347d2SRichard Henderson } else { 35826fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 35830b1347d2SRichard Henderson } 358430878590SRichard Henderson save_gpr(ctx, a->t, dest); 35850b1347d2SRichard Henderson 35860b1347d2SRichard Henderson /* Install the new nullification. */ 35870b1347d2SRichard Henderson cond_free(&ctx->null_cond); 358830878590SRichard Henderson if (a->c) { 3589bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35900b1347d2SRichard Henderson } 359131234768SRichard Henderson return nullify_end(ctx); 35920b1347d2SRichard Henderson } 35930b1347d2SRichard Henderson 359472ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 35950b1347d2SRichard Henderson { 359672ae4f2bSRichard Henderson unsigned len, width; 3597c53e401eSRichard Henderson uint64_t mask0, mask1; 35986fd0c7bcSRichard Henderson TCGv_i64 dest; 35990b1347d2SRichard Henderson 360072ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 360172ae4f2bSRichard Henderson return false; 360272ae4f2bSRichard Henderson } 360330878590SRichard Henderson if (a->c) { 36040b1347d2SRichard Henderson nullify_over(ctx); 36050b1347d2SRichard Henderson } 360672ae4f2bSRichard Henderson 360772ae4f2bSRichard Henderson len = a->len; 360872ae4f2bSRichard Henderson width = a->d ? 64 : 32; 360972ae4f2bSRichard Henderson if (a->cpos + len > width) { 361072ae4f2bSRichard Henderson len = width - a->cpos; 36110b1347d2SRichard Henderson } 36120b1347d2SRichard Henderson 361330878590SRichard Henderson dest = dest_gpr(ctx, a->t); 361430878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 361530878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 36160b1347d2SRichard Henderson 361730878590SRichard Henderson if (a->nz) { 36186fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 36196fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 36206fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 36210b1347d2SRichard Henderson } else { 36226fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 36230b1347d2SRichard Henderson } 362430878590SRichard Henderson save_gpr(ctx, a->t, dest); 36250b1347d2SRichard Henderson 36260b1347d2SRichard Henderson /* Install the new nullification. */ 36270b1347d2SRichard Henderson cond_free(&ctx->null_cond); 362830878590SRichard Henderson if (a->c) { 362972ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36300b1347d2SRichard Henderson } 363131234768SRichard Henderson return nullify_end(ctx); 36320b1347d2SRichard Henderson } 36330b1347d2SRichard Henderson 363472ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 36350b1347d2SRichard Henderson { 363630878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 363772ae4f2bSRichard Henderson unsigned len, width; 36386fd0c7bcSRichard Henderson TCGv_i64 dest, val; 36390b1347d2SRichard Henderson 364072ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 364172ae4f2bSRichard Henderson return false; 364272ae4f2bSRichard Henderson } 364330878590SRichard Henderson if (a->c) { 36440b1347d2SRichard Henderson nullify_over(ctx); 36450b1347d2SRichard Henderson } 364672ae4f2bSRichard Henderson 364772ae4f2bSRichard Henderson len = a->len; 364872ae4f2bSRichard Henderson width = a->d ? 64 : 32; 364972ae4f2bSRichard Henderson if (a->cpos + len > width) { 365072ae4f2bSRichard Henderson len = width - a->cpos; 36510b1347d2SRichard Henderson } 36520b1347d2SRichard Henderson 365330878590SRichard Henderson dest = dest_gpr(ctx, a->t); 365430878590SRichard Henderson val = load_gpr(ctx, a->r); 36550b1347d2SRichard Henderson if (rs == 0) { 36566fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 36570b1347d2SRichard Henderson } else { 36586fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 36590b1347d2SRichard Henderson } 366030878590SRichard Henderson save_gpr(ctx, a->t, dest); 36610b1347d2SRichard Henderson 36620b1347d2SRichard Henderson /* Install the new nullification. */ 36630b1347d2SRichard Henderson cond_free(&ctx->null_cond); 366430878590SRichard Henderson if (a->c) { 366572ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36660b1347d2SRichard Henderson } 366731234768SRichard Henderson return nullify_end(ctx); 36680b1347d2SRichard Henderson } 36690b1347d2SRichard Henderson 367072ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 36716fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 36720b1347d2SRichard Henderson { 36730b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 367472ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 36756fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3676c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 36770b1347d2SRichard Henderson 36780b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3679aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3680aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 36810b1347d2SRichard Henderson 36820b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 36836fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 36846fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 36850b1347d2SRichard Henderson 3686aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 36876fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 36886fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 36890b1347d2SRichard Henderson if (rs) { 36906fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 36916fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 36926fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 36936fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 36940b1347d2SRichard Henderson } else { 36956fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 36960b1347d2SRichard Henderson } 36970b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 36980b1347d2SRichard Henderson 36990b1347d2SRichard Henderson /* Install the new nullification. */ 37000b1347d2SRichard Henderson cond_free(&ctx->null_cond); 37010b1347d2SRichard Henderson if (c) { 370272ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 37030b1347d2SRichard Henderson } 370431234768SRichard Henderson return nullify_end(ctx); 37050b1347d2SRichard Henderson } 37060b1347d2SRichard Henderson 370772ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 370830878590SRichard Henderson { 370972ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 371072ae4f2bSRichard Henderson return false; 371172ae4f2bSRichard Henderson } 3712a6deecceSSven Schnelle if (a->c) { 3713a6deecceSSven Schnelle nullify_over(ctx); 3714a6deecceSSven Schnelle } 371572ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 371672ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 371730878590SRichard Henderson } 371830878590SRichard Henderson 371972ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 372030878590SRichard Henderson { 372172ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 372272ae4f2bSRichard Henderson return false; 372372ae4f2bSRichard Henderson } 3724a6deecceSSven Schnelle if (a->c) { 3725a6deecceSSven Schnelle nullify_over(ctx); 3726a6deecceSSven Schnelle } 372772ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 37286fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 372930878590SRichard Henderson } 37300b1347d2SRichard Henderson 37318340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 373298cd9ca7SRichard Henderson { 37336fd0c7bcSRichard Henderson TCGv_i64 tmp; 373498cd9ca7SRichard Henderson 3735c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 373698cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 373798cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 373898cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 373998cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 374098cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 374198cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 374298cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 374398cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 37448340f534SRichard Henderson if (a->b == 0) { 37458340f534SRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 374698cd9ca7SRichard Henderson } 3747c301f34eSRichard Henderson #else 3748c301f34eSRichard Henderson nullify_over(ctx); 3749660eefe1SRichard Henderson #endif 3750660eefe1SRichard Henderson 3751aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37526fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp); 3753660eefe1SRichard Henderson tmp = do_ibranch_priv(ctx, tmp); 3754c301f34eSRichard Henderson 3755c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 37568340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3757c301f34eSRichard Henderson #else 3758c301f34eSRichard Henderson TCGv_i64 new_spc = tcg_temp_new_i64(); 3759c301f34eSRichard Henderson 37608340f534SRichard Henderson load_spr(ctx, new_spc, a->sp); 37618340f534SRichard Henderson if (a->l) { 3762741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); 3763c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); 3764c301f34eSRichard Henderson } 37658340f534SRichard Henderson if (a->n && use_nullify_skip(ctx)) { 3766a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 37676fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 3768a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3769c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, new_spc); 3770c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); 3771c301f34eSRichard Henderson } else { 3772741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3773c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3774c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3775c301f34eSRichard Henderson } 3776a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3777c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, new_spc); 37788340f534SRichard Henderson nullify_set(ctx, a->n); 3779c301f34eSRichard Henderson } 3780c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 378131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 378231234768SRichard Henderson return nullify_end(ctx); 3783c301f34eSRichard Henderson #endif 378498cd9ca7SRichard Henderson } 378598cd9ca7SRichard Henderson 37868340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 378798cd9ca7SRichard Henderson { 37888340f534SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n); 378998cd9ca7SRichard Henderson } 379098cd9ca7SRichard Henderson 37918340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 379243e05652SRichard Henderson { 3793c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, a->disp); 379443e05652SRichard Henderson 37956e5f5300SSven Schnelle nullify_over(ctx); 37966e5f5300SSven Schnelle 379743e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 379843e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 379943e05652SRichard Henderson * expensive to track. Real hardware will trap for 380043e05652SRichard Henderson * b gateway 380143e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 380243e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 380343e05652SRichard Henderson * diagnose the security hole 380443e05652SRichard Henderson * b gateway 380543e05652SRichard Henderson * b evil 380643e05652SRichard Henderson * in which instructions at evil would run with increased privs. 380743e05652SRichard Henderson */ 380843e05652SRichard Henderson if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) { 380943e05652SRichard Henderson return gen_illegal(ctx); 381043e05652SRichard Henderson } 381143e05652SRichard Henderson 381243e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 381343e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 3814*94956d7bSPhilippe Mathieu-Daudé int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next); 381543e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 381643e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 381743e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 381843e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 381943e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 382043e05652SRichard Henderson if (type < 0) { 382131234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 382231234768SRichard Henderson return true; 382343e05652SRichard Henderson } 382443e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 382543e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 382643e05652SRichard Henderson dest = deposit32(dest, 0, 2, type - 4); 382743e05652SRichard Henderson } 382843e05652SRichard Henderson } else { 382943e05652SRichard Henderson dest &= -4; /* priv = 0 */ 383043e05652SRichard Henderson } 383143e05652SRichard Henderson #endif 383243e05652SRichard Henderson 38336e5f5300SSven Schnelle if (a->l) { 38346fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 38356e5f5300SSven Schnelle if (ctx->privilege < 3) { 38366fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 38376e5f5300SSven Schnelle } 38386fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 38396e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 38406e5f5300SSven Schnelle } 38416e5f5300SSven Schnelle 38426e5f5300SSven Schnelle return do_dbranch(ctx, dest, 0, a->n); 384343e05652SRichard Henderson } 384443e05652SRichard Henderson 38458340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 384698cd9ca7SRichard Henderson { 3847b35aec85SRichard Henderson if (a->x) { 3848aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 38496fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3); 38506fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8); 3851660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 38528340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3853b35aec85SRichard Henderson } else { 3854b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 3855b35aec85SRichard Henderson return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n); 3856b35aec85SRichard Henderson } 385798cd9ca7SRichard Henderson } 385898cd9ca7SRichard Henderson 38598340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 386098cd9ca7SRichard Henderson { 38616fd0c7bcSRichard Henderson TCGv_i64 dest; 386298cd9ca7SRichard Henderson 38638340f534SRichard Henderson if (a->x == 0) { 38648340f534SRichard Henderson dest = load_gpr(ctx, a->b); 386598cd9ca7SRichard Henderson } else { 3866aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 38676fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 38686fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 386998cd9ca7SRichard Henderson } 3870660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 38718340f534SRichard Henderson return do_ibranch(ctx, dest, 0, a->n); 387298cd9ca7SRichard Henderson } 387398cd9ca7SRichard Henderson 38748340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 387598cd9ca7SRichard Henderson { 38766fd0c7bcSRichard Henderson TCGv_i64 dest; 387798cd9ca7SRichard Henderson 3878c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 38798340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 38808340f534SRichard Henderson return do_ibranch(ctx, dest, a->l, a->n); 3881c301f34eSRichard Henderson #else 3882c301f34eSRichard Henderson nullify_over(ctx); 38838340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3884c301f34eSRichard Henderson 3885741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3886c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3887c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3888c301f34eSRichard Henderson } 3889741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest); 3890c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); 38918340f534SRichard Henderson if (a->l) { 3892741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var); 3893c301f34eSRichard Henderson } 38948340f534SRichard Henderson nullify_set(ctx, a->n); 3895c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 389631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 389731234768SRichard Henderson return nullify_end(ctx); 3898c301f34eSRichard Henderson #endif 389998cd9ca7SRichard Henderson } 390098cd9ca7SRichard Henderson 3901a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 3902a8966ba7SRichard Henderson { 3903a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 3904a8966ba7SRichard Henderson return ctx->is_pa20; 3905a8966ba7SRichard Henderson } 3906a8966ba7SRichard Henderson 39071ca74648SRichard Henderson /* 39081ca74648SRichard Henderson * Float class 0 39091ca74648SRichard Henderson */ 3910ebe9383cSRichard Henderson 39111ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3912ebe9383cSRichard Henderson { 3913ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3914ebe9383cSRichard Henderson } 3915ebe9383cSRichard Henderson 391659f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 391759f8c04bSHelge Deller { 3918a300dad3SRichard Henderson uint64_t ret; 3919a300dad3SRichard Henderson 3920c53e401eSRichard Henderson if (ctx->is_pa20) { 3921a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 3922a300dad3SRichard Henderson } else { 3923a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 3924a300dad3SRichard Henderson } 3925a300dad3SRichard Henderson 392659f8c04bSHelge Deller nullify_over(ctx); 3927a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 392859f8c04bSHelge Deller return nullify_end(ctx); 392959f8c04bSHelge Deller } 393059f8c04bSHelge Deller 39311ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 39321ca74648SRichard Henderson { 39331ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 39341ca74648SRichard Henderson } 39351ca74648SRichard Henderson 3936ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3937ebe9383cSRichard Henderson { 3938ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 3939ebe9383cSRichard Henderson } 3940ebe9383cSRichard Henderson 39411ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 39421ca74648SRichard Henderson { 39431ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 39441ca74648SRichard Henderson } 39451ca74648SRichard Henderson 39461ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3947ebe9383cSRichard Henderson { 3948ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 3949ebe9383cSRichard Henderson } 3950ebe9383cSRichard Henderson 39511ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 39521ca74648SRichard Henderson { 39531ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 39541ca74648SRichard Henderson } 39551ca74648SRichard Henderson 3956ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3957ebe9383cSRichard Henderson { 3958ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 3959ebe9383cSRichard Henderson } 3960ebe9383cSRichard Henderson 39611ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 39621ca74648SRichard Henderson { 39631ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 39641ca74648SRichard Henderson } 39651ca74648SRichard Henderson 39661ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 39671ca74648SRichard Henderson { 39681ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 39691ca74648SRichard Henderson } 39701ca74648SRichard Henderson 39711ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 39721ca74648SRichard Henderson { 39731ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 39741ca74648SRichard Henderson } 39751ca74648SRichard Henderson 39761ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 39771ca74648SRichard Henderson { 39781ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 39791ca74648SRichard Henderson } 39801ca74648SRichard Henderson 39811ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 39821ca74648SRichard Henderson { 39831ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 39841ca74648SRichard Henderson } 39851ca74648SRichard Henderson 39861ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3987ebe9383cSRichard Henderson { 3988ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 3989ebe9383cSRichard Henderson } 3990ebe9383cSRichard Henderson 39911ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 39921ca74648SRichard Henderson { 39931ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 39941ca74648SRichard Henderson } 39951ca74648SRichard Henderson 3996ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3997ebe9383cSRichard Henderson { 3998ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 3999ebe9383cSRichard Henderson } 4000ebe9383cSRichard Henderson 40011ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 40021ca74648SRichard Henderson { 40031ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 40041ca74648SRichard Henderson } 40051ca74648SRichard Henderson 40061ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4007ebe9383cSRichard Henderson { 4008ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 4009ebe9383cSRichard Henderson } 4010ebe9383cSRichard Henderson 40111ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 40121ca74648SRichard Henderson { 40131ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 40141ca74648SRichard Henderson } 40151ca74648SRichard Henderson 4016ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4017ebe9383cSRichard Henderson { 4018ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4019ebe9383cSRichard Henderson } 4020ebe9383cSRichard Henderson 40211ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 40221ca74648SRichard Henderson { 40231ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 40241ca74648SRichard Henderson } 40251ca74648SRichard Henderson 40261ca74648SRichard Henderson /* 40271ca74648SRichard Henderson * Float class 1 40281ca74648SRichard Henderson */ 40291ca74648SRichard Henderson 40301ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 40311ca74648SRichard Henderson { 40321ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 40331ca74648SRichard Henderson } 40341ca74648SRichard Henderson 40351ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 40361ca74648SRichard Henderson { 40371ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 40381ca74648SRichard Henderson } 40391ca74648SRichard Henderson 40401ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 40411ca74648SRichard Henderson { 40421ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 40431ca74648SRichard Henderson } 40441ca74648SRichard Henderson 40451ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 40461ca74648SRichard Henderson { 40471ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 40481ca74648SRichard Henderson } 40491ca74648SRichard Henderson 40501ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 40511ca74648SRichard Henderson { 40521ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 40531ca74648SRichard Henderson } 40541ca74648SRichard Henderson 40551ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 40561ca74648SRichard Henderson { 40571ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 40581ca74648SRichard Henderson } 40591ca74648SRichard Henderson 40601ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 40611ca74648SRichard Henderson { 40621ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 40631ca74648SRichard Henderson } 40641ca74648SRichard Henderson 40651ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 40661ca74648SRichard Henderson { 40671ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 40681ca74648SRichard Henderson } 40691ca74648SRichard Henderson 40701ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 40711ca74648SRichard Henderson { 40721ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 40731ca74648SRichard Henderson } 40741ca74648SRichard Henderson 40751ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 40761ca74648SRichard Henderson { 40771ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 40781ca74648SRichard Henderson } 40791ca74648SRichard Henderson 40801ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 40811ca74648SRichard Henderson { 40821ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 40831ca74648SRichard Henderson } 40841ca74648SRichard Henderson 40851ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 40861ca74648SRichard Henderson { 40871ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 40881ca74648SRichard Henderson } 40891ca74648SRichard Henderson 40901ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 40911ca74648SRichard Henderson { 40921ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 40931ca74648SRichard Henderson } 40941ca74648SRichard Henderson 40951ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 40961ca74648SRichard Henderson { 40971ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 40981ca74648SRichard Henderson } 40991ca74648SRichard Henderson 41001ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 41011ca74648SRichard Henderson { 41021ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 41031ca74648SRichard Henderson } 41041ca74648SRichard Henderson 41051ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 41061ca74648SRichard Henderson { 41071ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 41081ca74648SRichard Henderson } 41091ca74648SRichard Henderson 41101ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 41111ca74648SRichard Henderson { 41121ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 41131ca74648SRichard Henderson } 41141ca74648SRichard Henderson 41151ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 41161ca74648SRichard Henderson { 41171ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 41181ca74648SRichard Henderson } 41191ca74648SRichard Henderson 41201ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 41211ca74648SRichard Henderson { 41221ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 41231ca74648SRichard Henderson } 41241ca74648SRichard Henderson 41251ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 41261ca74648SRichard Henderson { 41271ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 41281ca74648SRichard Henderson } 41291ca74648SRichard Henderson 41301ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 41311ca74648SRichard Henderson { 41321ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 41331ca74648SRichard Henderson } 41341ca74648SRichard Henderson 41351ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 41361ca74648SRichard Henderson { 41371ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 41381ca74648SRichard Henderson } 41391ca74648SRichard Henderson 41401ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 41411ca74648SRichard Henderson { 41421ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 41431ca74648SRichard Henderson } 41441ca74648SRichard Henderson 41451ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 41461ca74648SRichard Henderson { 41471ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 41481ca74648SRichard Henderson } 41491ca74648SRichard Henderson 41501ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 41511ca74648SRichard Henderson { 41521ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 41531ca74648SRichard Henderson } 41541ca74648SRichard Henderson 41551ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 41561ca74648SRichard Henderson { 41571ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 41581ca74648SRichard Henderson } 41591ca74648SRichard Henderson 41601ca74648SRichard Henderson /* 41611ca74648SRichard Henderson * Float class 2 41621ca74648SRichard Henderson */ 41631ca74648SRichard Henderson 41641ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4165ebe9383cSRichard Henderson { 4166ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4167ebe9383cSRichard Henderson 4168ebe9383cSRichard Henderson nullify_over(ctx); 4169ebe9383cSRichard Henderson 41701ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 41711ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 417229dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 417329dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4174ebe9383cSRichard Henderson 4175ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4176ebe9383cSRichard Henderson 41771ca74648SRichard Henderson return nullify_end(ctx); 4178ebe9383cSRichard Henderson } 4179ebe9383cSRichard Henderson 41801ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4181ebe9383cSRichard Henderson { 4182ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4183ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4184ebe9383cSRichard Henderson 4185ebe9383cSRichard Henderson nullify_over(ctx); 4186ebe9383cSRichard Henderson 41871ca74648SRichard Henderson ta = load_frd0(a->r1); 41881ca74648SRichard Henderson tb = load_frd0(a->r2); 418929dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 419029dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4191ebe9383cSRichard Henderson 4192ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4193ebe9383cSRichard Henderson 419431234768SRichard Henderson return nullify_end(ctx); 4195ebe9383cSRichard Henderson } 4196ebe9383cSRichard Henderson 41971ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4198ebe9383cSRichard Henderson { 41996fd0c7bcSRichard Henderson TCGv_i64 t; 4200ebe9383cSRichard Henderson 4201ebe9383cSRichard Henderson nullify_over(ctx); 4202ebe9383cSRichard Henderson 4203aac0f603SRichard Henderson t = tcg_temp_new_i64(); 42046fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4205ebe9383cSRichard Henderson 42061ca74648SRichard Henderson if (a->y == 1) { 4207ebe9383cSRichard Henderson int mask; 4208ebe9383cSRichard Henderson bool inv = false; 4209ebe9383cSRichard Henderson 42101ca74648SRichard Henderson switch (a->c) { 4211ebe9383cSRichard Henderson case 0: /* simple */ 42126fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 4213ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4214ebe9383cSRichard Henderson goto done; 4215ebe9383cSRichard Henderson case 2: /* rej */ 4216ebe9383cSRichard Henderson inv = true; 4217ebe9383cSRichard Henderson /* fallthru */ 4218ebe9383cSRichard Henderson case 1: /* acc */ 4219ebe9383cSRichard Henderson mask = 0x43ff800; 4220ebe9383cSRichard Henderson break; 4221ebe9383cSRichard Henderson case 6: /* rej8 */ 4222ebe9383cSRichard Henderson inv = true; 4223ebe9383cSRichard Henderson /* fallthru */ 4224ebe9383cSRichard Henderson case 5: /* acc8 */ 4225ebe9383cSRichard Henderson mask = 0x43f8000; 4226ebe9383cSRichard Henderson break; 4227ebe9383cSRichard Henderson case 9: /* acc6 */ 4228ebe9383cSRichard Henderson mask = 0x43e0000; 4229ebe9383cSRichard Henderson break; 4230ebe9383cSRichard Henderson case 13: /* acc4 */ 4231ebe9383cSRichard Henderson mask = 0x4380000; 4232ebe9383cSRichard Henderson break; 4233ebe9383cSRichard Henderson case 17: /* acc2 */ 4234ebe9383cSRichard Henderson mask = 0x4200000; 4235ebe9383cSRichard Henderson break; 4236ebe9383cSRichard Henderson default: 42371ca74648SRichard Henderson gen_illegal(ctx); 42381ca74648SRichard Henderson return true; 4239ebe9383cSRichard Henderson } 4240ebe9383cSRichard Henderson if (inv) { 42416fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 42426fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 4243ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 4244ebe9383cSRichard Henderson } else { 42456fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 4246ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 4247ebe9383cSRichard Henderson } 42481ca74648SRichard Henderson } else { 42491ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 42501ca74648SRichard Henderson 42516fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 42521ca74648SRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 42531ca74648SRichard Henderson } 42541ca74648SRichard Henderson 4255ebe9383cSRichard Henderson done: 425631234768SRichard Henderson return nullify_end(ctx); 4257ebe9383cSRichard Henderson } 4258ebe9383cSRichard Henderson 42591ca74648SRichard Henderson /* 42601ca74648SRichard Henderson * Float class 2 42611ca74648SRichard Henderson */ 42621ca74648SRichard Henderson 42631ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4264ebe9383cSRichard Henderson { 42651ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 42661ca74648SRichard Henderson } 42671ca74648SRichard Henderson 42681ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 42691ca74648SRichard Henderson { 42701ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 42711ca74648SRichard Henderson } 42721ca74648SRichard Henderson 42731ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 42741ca74648SRichard Henderson { 42751ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 42761ca74648SRichard Henderson } 42771ca74648SRichard Henderson 42781ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 42791ca74648SRichard Henderson { 42801ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 42811ca74648SRichard Henderson } 42821ca74648SRichard Henderson 42831ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 42841ca74648SRichard Henderson { 42851ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 42861ca74648SRichard Henderson } 42871ca74648SRichard Henderson 42881ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 42891ca74648SRichard Henderson { 42901ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 42911ca74648SRichard Henderson } 42921ca74648SRichard Henderson 42931ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 42941ca74648SRichard Henderson { 42951ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 42961ca74648SRichard Henderson } 42971ca74648SRichard Henderson 42981ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 42991ca74648SRichard Henderson { 43001ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 43011ca74648SRichard Henderson } 43021ca74648SRichard Henderson 43031ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 43041ca74648SRichard Henderson { 43051ca74648SRichard Henderson TCGv_i64 x, y; 4306ebe9383cSRichard Henderson 4307ebe9383cSRichard Henderson nullify_over(ctx); 4308ebe9383cSRichard Henderson 43091ca74648SRichard Henderson x = load_frw0_i64(a->r1); 43101ca74648SRichard Henderson y = load_frw0_i64(a->r2); 43111ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 43121ca74648SRichard Henderson save_frd(a->t, x); 4313ebe9383cSRichard Henderson 431431234768SRichard Henderson return nullify_end(ctx); 4315ebe9383cSRichard Henderson } 4316ebe9383cSRichard Henderson 4317ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4318ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4319ebe9383cSRichard Henderson { 4320ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4321ebe9383cSRichard Henderson } 4322ebe9383cSRichard Henderson 4323b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4324ebe9383cSRichard Henderson { 4325b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4326b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4327b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4328b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4329b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4330ebe9383cSRichard Henderson 4331ebe9383cSRichard Henderson nullify_over(ctx); 4332ebe9383cSRichard Henderson 4333ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4334ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4335ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4336ebe9383cSRichard Henderson 433731234768SRichard Henderson return nullify_end(ctx); 4338ebe9383cSRichard Henderson } 4339ebe9383cSRichard Henderson 4340b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4341b1e2af57SRichard Henderson { 4342b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4343b1e2af57SRichard Henderson } 4344b1e2af57SRichard Henderson 4345b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4346b1e2af57SRichard Henderson { 4347b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4348b1e2af57SRichard Henderson } 4349b1e2af57SRichard Henderson 4350b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4351b1e2af57SRichard Henderson { 4352b1e2af57SRichard Henderson nullify_over(ctx); 4353b1e2af57SRichard Henderson 4354b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4355b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4356b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4357b1e2af57SRichard Henderson 4358b1e2af57SRichard Henderson return nullify_end(ctx); 4359b1e2af57SRichard Henderson } 4360b1e2af57SRichard Henderson 4361b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4362b1e2af57SRichard Henderson { 4363b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4364b1e2af57SRichard Henderson } 4365b1e2af57SRichard Henderson 4366b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4367b1e2af57SRichard Henderson { 4368b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4369b1e2af57SRichard Henderson } 4370b1e2af57SRichard Henderson 4371c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4372ebe9383cSRichard Henderson { 4373c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4374ebe9383cSRichard Henderson 4375ebe9383cSRichard Henderson nullify_over(ctx); 4376c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4377c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4378c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4379ebe9383cSRichard Henderson 4380c3bad4f8SRichard Henderson if (a->neg) { 4381ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4382ebe9383cSRichard Henderson } else { 4383ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4384ebe9383cSRichard Henderson } 4385ebe9383cSRichard Henderson 4386c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 438731234768SRichard Henderson return nullify_end(ctx); 4388ebe9383cSRichard Henderson } 4389ebe9383cSRichard Henderson 4390c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4391ebe9383cSRichard Henderson { 4392c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4393ebe9383cSRichard Henderson 4394ebe9383cSRichard Henderson nullify_over(ctx); 4395c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4396c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4397c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4398ebe9383cSRichard Henderson 4399c3bad4f8SRichard Henderson if (a->neg) { 4400ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4401ebe9383cSRichard Henderson } else { 4402ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4403ebe9383cSRichard Henderson } 4404ebe9383cSRichard Henderson 4405c3bad4f8SRichard Henderson save_frd(a->t, x); 440631234768SRichard Henderson return nullify_end(ctx); 4407ebe9383cSRichard Henderson } 4408ebe9383cSRichard Henderson 440915da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a) 441015da177bSSven Schnelle { 4411cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4412cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4413cf6b28d4SHelge Deller if (a->i == 0x100) { 4414cf6b28d4SHelge Deller /* emulate PDC BTLB, called by SeaBIOS-hppa */ 4415ad75a51eSRichard Henderson nullify_over(ctx); 4416ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4417cf6b28d4SHelge Deller return nullify_end(ctx); 441815da177bSSven Schnelle } 4419dbca0835SHelge Deller if (a->i == 0x101) { 4420dbca0835SHelge Deller /* print char in %r26 to first serial console, used by SeaBIOS-hppa */ 4421dbca0835SHelge Deller nullify_over(ctx); 4422dbca0835SHelge Deller gen_helper_diag_console_output(tcg_env); 4423dbca0835SHelge Deller return nullify_end(ctx); 4424dbca0835SHelge Deller } 4425ad75a51eSRichard Henderson #endif 4426ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4427ad75a51eSRichard Henderson return true; 4428ad75a51eSRichard Henderson } 442915da177bSSven Schnelle 4430b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 443161766fe9SRichard Henderson { 443251b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4433f764718dSRichard Henderson int bound; 443461766fe9SRichard Henderson 443551b061fbSRichard Henderson ctx->cs = cs; 4436494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4437bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 44383d68ee7bSRichard Henderson 44393d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4440c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 44413d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 4442c01e5dfbSHelge Deller ctx->iaoq_f = ctx->base.pc_first | ctx->privilege; 4443c01e5dfbSHelge Deller ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege; 4444217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4445c301f34eSRichard Henderson #else 4446494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4447bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4448bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4449451d993dSRichard Henderson : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX); 44503d68ee7bSRichard Henderson 4451c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4452c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4453c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4454c301f34eSRichard Henderson int32_t diff = cs_base; 4455c301f34eSRichard Henderson 4456c301f34eSRichard Henderson ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4457c301f34eSRichard Henderson ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); 4458c301f34eSRichard Henderson #endif 445951b061fbSRichard Henderson ctx->iaoq_n = -1; 4460f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 446161766fe9SRichard Henderson 4462a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4463a4db4a78SRichard Henderson 44643d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 44653d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4466b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 446761766fe9SRichard Henderson } 446861766fe9SRichard Henderson 446951b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 447051b061fbSRichard Henderson { 447151b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 447261766fe9SRichard Henderson 44733d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 447451b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 447551b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4476494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 447751b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 447851b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4479129e9cc3SRichard Henderson } 448051b061fbSRichard Henderson ctx->null_lab = NULL; 448161766fe9SRichard Henderson } 448261766fe9SRichard Henderson 448351b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 448451b061fbSRichard Henderson { 448551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 448651b061fbSRichard Henderson 4487f5b5c857SRichard Henderson tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0); 4488f5b5c857SRichard Henderson ctx->insn_start = tcg_last_op(); 448951b061fbSRichard Henderson } 449051b061fbSRichard Henderson 449151b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 449251b061fbSRichard Henderson { 449351b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4494b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 449551b061fbSRichard Henderson DisasJumpType ret; 449651b061fbSRichard Henderson 449751b061fbSRichard Henderson /* Execute one insn. */ 4498ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4499c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 450031234768SRichard Henderson do_page_zero(ctx); 450131234768SRichard Henderson ret = ctx->base.is_jmp; 4502869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4503ba1d0b44SRichard Henderson } else 4504ba1d0b44SRichard Henderson #endif 4505ba1d0b44SRichard Henderson { 450661766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 450761766fe9SRichard Henderson the page permissions for execute. */ 45084e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 450961766fe9SRichard Henderson 451061766fe9SRichard Henderson /* Set up the IA queue for the next insn. 451161766fe9SRichard Henderson This will be overwritten by a branch. */ 451251b061fbSRichard Henderson if (ctx->iaoq_b == -1) { 451351b061fbSRichard Henderson ctx->iaoq_n = -1; 4514aac0f603SRichard Henderson ctx->iaoq_n_var = tcg_temp_new_i64(); 45156fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 451661766fe9SRichard Henderson } else { 451751b061fbSRichard Henderson ctx->iaoq_n = ctx->iaoq_b + 4; 4518f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 451961766fe9SRichard Henderson } 452061766fe9SRichard Henderson 452151b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 452251b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4523869051eaSRichard Henderson ret = DISAS_NEXT; 4524129e9cc3SRichard Henderson } else { 45251a19da0dSRichard Henderson ctx->insn = insn; 452631274b46SRichard Henderson if (!decode(ctx, insn)) { 452731274b46SRichard Henderson gen_illegal(ctx); 452831274b46SRichard Henderson } 452931234768SRichard Henderson ret = ctx->base.is_jmp; 453051b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4531129e9cc3SRichard Henderson } 453261766fe9SRichard Henderson } 453361766fe9SRichard Henderson 45343d68ee7bSRichard Henderson /* Advance the insn queue. Note that this check also detects 45353d68ee7bSRichard Henderson a priority change within the instruction queue. */ 453651b061fbSRichard Henderson if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 4537c301f34eSRichard Henderson if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 4538c301f34eSRichard Henderson && use_goto_tb(ctx, ctx->iaoq_b) 4539c301f34eSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4540c301f34eSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 454151b061fbSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 454251b061fbSRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 454331234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_NORETURN; 4544129e9cc3SRichard Henderson } else { 454531234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE; 454661766fe9SRichard Henderson } 4547129e9cc3SRichard Henderson } 454851b061fbSRichard Henderson ctx->iaoq_f = ctx->iaoq_b; 454951b061fbSRichard Henderson ctx->iaoq_b = ctx->iaoq_n; 4550c301f34eSRichard Henderson ctx->base.pc_next += 4; 455161766fe9SRichard Henderson 4552c5d0aec2SRichard Henderson switch (ret) { 4553c5d0aec2SRichard Henderson case DISAS_NORETURN: 4554c5d0aec2SRichard Henderson case DISAS_IAQ_N_UPDATED: 4555c5d0aec2SRichard Henderson break; 4556c5d0aec2SRichard Henderson 4557c5d0aec2SRichard Henderson case DISAS_NEXT: 4558c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE: 4559c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 456051b061fbSRichard Henderson if (ctx->iaoq_f == -1) { 4561a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b); 4562741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 4563c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY 4564c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 4565c301f34eSRichard Henderson #endif 456651b061fbSRichard Henderson nullify_save(ctx); 4567c5d0aec2SRichard Henderson ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT 4568c5d0aec2SRichard Henderson ? DISAS_EXIT 4569c5d0aec2SRichard Henderson : DISAS_IAQ_N_UPDATED); 457051b061fbSRichard Henderson } else if (ctx->iaoq_b == -1) { 4571a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var); 457261766fe9SRichard Henderson } 4573c5d0aec2SRichard Henderson break; 4574c5d0aec2SRichard Henderson 4575c5d0aec2SRichard Henderson default: 4576c5d0aec2SRichard Henderson g_assert_not_reached(); 4577c5d0aec2SRichard Henderson } 457861766fe9SRichard Henderson } 457961766fe9SRichard Henderson 458051b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 458151b061fbSRichard Henderson { 458251b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4583e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 458451b061fbSRichard Henderson 4585e1b5a5edSRichard Henderson switch (is_jmp) { 4586869051eaSRichard Henderson case DISAS_NORETURN: 458761766fe9SRichard Henderson break; 458851b061fbSRichard Henderson case DISAS_TOO_MANY: 4589869051eaSRichard Henderson case DISAS_IAQ_N_STALE: 4590e1b5a5edSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4591741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 4592741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 459351b061fbSRichard Henderson nullify_save(ctx); 459461766fe9SRichard Henderson /* FALLTHRU */ 4595869051eaSRichard Henderson case DISAS_IAQ_N_UPDATED: 45968532a14eSRichard Henderson if (is_jmp != DISAS_IAQ_N_STALE_EXIT) { 45977f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 45988532a14eSRichard Henderson break; 459961766fe9SRichard Henderson } 4600c5d0aec2SRichard Henderson /* FALLTHRU */ 4601c5d0aec2SRichard Henderson case DISAS_EXIT: 4602c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 460361766fe9SRichard Henderson break; 460461766fe9SRichard Henderson default: 460551b061fbSRichard Henderson g_assert_not_reached(); 460661766fe9SRichard Henderson } 460751b061fbSRichard Henderson } 460861766fe9SRichard Henderson 46098eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 46108eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 461151b061fbSRichard Henderson { 4612c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 461361766fe9SRichard Henderson 4614ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4615ba1d0b44SRichard Henderson switch (pc) { 46167ad439dfSRichard Henderson case 0x00: 46178eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4618ba1d0b44SRichard Henderson return; 46197ad439dfSRichard Henderson case 0xb0: 46208eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4621ba1d0b44SRichard Henderson return; 46227ad439dfSRichard Henderson case 0xe0: 46238eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4624ba1d0b44SRichard Henderson return; 46257ad439dfSRichard Henderson case 0x100: 46268eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4627ba1d0b44SRichard Henderson return; 46287ad439dfSRichard Henderson } 4629ba1d0b44SRichard Henderson #endif 4630ba1d0b44SRichard Henderson 46318eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 46328eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 463361766fe9SRichard Henderson } 463451b061fbSRichard Henderson 463551b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 463651b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 463751b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 463851b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 463951b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 464051b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 464151b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 464251b061fbSRichard Henderson }; 464351b061fbSRichard Henderson 4644597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 464532f0c394SAnton Johansson vaddr pc, void *host_pc) 464651b061fbSRichard Henderson { 464751b061fbSRichard Henderson DisasContext ctx; 4648306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 464961766fe9SRichard Henderson } 4650