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 73217d1a5eSRichard Henderson #else 742d4afb03SRichard Henderson #define UNALIGN(C) MO_ALIGN 75217d1a5eSRichard Henderson #endif 76217d1a5eSRichard Henderson 77e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 78451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val) 79e36f27efSRichard Henderson { 80881d1073SHelge Deller /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */ 81881d1073SHelge Deller if (ctx->is_pa20) { 82e36f27efSRichard Henderson if (val & PSW_SM_W) { 83881d1073SHelge Deller val |= PSW_W; 84881d1073SHelge Deller } 85881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_G); 86881d1073SHelge Deller } else { 87881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_O); 88e36f27efSRichard Henderson } 89e36f27efSRichard Henderson return val; 90e36f27efSRichard Henderson } 91e36f27efSRichard Henderson 92deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base. */ 93451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val) 94deee69a1SRichard Henderson { 95deee69a1SRichard Henderson return ~val; 96deee69a1SRichard Henderson } 97deee69a1SRichard Henderson 981cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value 991cd012a5SRichard Henderson we use for the final M. */ 100451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val) 1011cd012a5SRichard Henderson { 1021cd012a5SRichard Henderson return val & 2 ? (val & 1 ? -1 : 1) : 0; 1031cd012a5SRichard Henderson } 1041cd012a5SRichard Henderson 105740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify. */ 106451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val) 107740038d7SRichard Henderson { 108740038d7SRichard Henderson return val ? 1 : -1; 109740038d7SRichard Henderson } 110740038d7SRichard Henderson 111451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val) 112740038d7SRichard Henderson { 113740038d7SRichard Henderson return val ? -1 : 1; 114740038d7SRichard Henderson } 115740038d7SRichard Henderson 116740038d7SRichard Henderson /* Used for branch targets and fp memory ops. */ 117451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val) 11801afb7beSRichard Henderson { 11901afb7beSRichard Henderson return val << 2; 12001afb7beSRichard Henderson } 12101afb7beSRichard Henderson 122740038d7SRichard Henderson /* Used for fp memory ops. */ 123451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val) 124740038d7SRichard Henderson { 125740038d7SRichard Henderson return val << 3; 126740038d7SRichard Henderson } 127740038d7SRichard Henderson 1280588e061SRichard Henderson /* Used for assemble_21. */ 129451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val) 1300588e061SRichard Henderson { 1310588e061SRichard Henderson return val << 11; 1320588e061SRichard Henderson } 1330588e061SRichard Henderson 13472ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val) 13572ae4f2bSRichard Henderson { 13672ae4f2bSRichard Henderson /* 13772ae4f2bSRichard Henderson * Officially, 32 * x + 32 - y. 13872ae4f2bSRichard Henderson * Here, x is already in bit 5, and y is [4:0]. 13972ae4f2bSRichard Henderson * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1, 14072ae4f2bSRichard Henderson * with the overflow from bit 4 summing with x. 14172ae4f2bSRichard Henderson */ 14272ae4f2bSRichard Henderson return (val ^ 31) + 1; 14372ae4f2bSRichard Henderson } 14472ae4f2bSRichard Henderson 145c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */ 146c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val) 147c65c3ee1SRichard Henderson { 148c65c3ee1SRichard Henderson return val ? val : 4; /* 0 == "*<<" */ 149c65c3ee1SRichard Henderson } 150c65c3ee1SRichard Henderson 15101afb7beSRichard Henderson 15240f9f908SRichard Henderson /* Include the auto-generated decoder. */ 153abff1abfSPaolo Bonzini #include "decode-insns.c.inc" 15440f9f908SRichard Henderson 15561766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 15661766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 157869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 15861766fe9SRichard Henderson 15961766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 16061766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 161869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 16261766fe9SRichard Henderson 163e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 164e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 165e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 166c5d0aec2SRichard Henderson #define DISAS_EXIT DISAS_TARGET_3 167e1b5a5edSRichard Henderson 16861766fe9SRichard Henderson /* global register indexes */ 1696fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32]; 17033423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 171494737b7SRichard Henderson static TCGv_i64 cpu_srH; 1726fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f; 1736fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b; 174c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 175c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 1766fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar; 1776fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n; 1786fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v; 1796fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb; 1806fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb; 18161766fe9SRichard Henderson 18261766fe9SRichard Henderson void hppa_translate_init(void) 18361766fe9SRichard Henderson { 18461766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 18561766fe9SRichard Henderson 1866fd0c7bcSRichard Henderson typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 18761766fe9SRichard Henderson static const GlobalVar vars[] = { 18835136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 18961766fe9SRichard Henderson DEF_VAR(psw_n), 19061766fe9SRichard Henderson DEF_VAR(psw_v), 19161766fe9SRichard Henderson DEF_VAR(psw_cb), 19261766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 19361766fe9SRichard Henderson DEF_VAR(iaoq_f), 19461766fe9SRichard Henderson DEF_VAR(iaoq_b), 19561766fe9SRichard Henderson }; 19661766fe9SRichard Henderson 19761766fe9SRichard Henderson #undef DEF_VAR 19861766fe9SRichard Henderson 19961766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 20061766fe9SRichard Henderson static const char gr_names[32][4] = { 20161766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 20261766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 20361766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 20461766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 20561766fe9SRichard Henderson }; 20633423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 207494737b7SRichard Henderson static const char sr_names[5][4] = { 208494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 20933423472SRichard Henderson }; 21061766fe9SRichard Henderson 21161766fe9SRichard Henderson int i; 21261766fe9SRichard Henderson 213f764718dSRichard Henderson cpu_gr[0] = NULL; 21461766fe9SRichard Henderson for (i = 1; i < 32; i++) { 215ad75a51eSRichard Henderson cpu_gr[i] = tcg_global_mem_new(tcg_env, 21661766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 21761766fe9SRichard Henderson gr_names[i]); 21861766fe9SRichard Henderson } 21933423472SRichard Henderson for (i = 0; i < 4; i++) { 220ad75a51eSRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 22133423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 22233423472SRichard Henderson sr_names[i]); 22333423472SRichard Henderson } 224ad75a51eSRichard Henderson cpu_srH = tcg_global_mem_new_i64(tcg_env, 225494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 226494737b7SRichard Henderson sr_names[4]); 22761766fe9SRichard Henderson 22861766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 22961766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 230ad75a51eSRichard Henderson *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 23161766fe9SRichard Henderson } 232c301f34eSRichard Henderson 233ad75a51eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 234c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 235c301f34eSRichard Henderson "iasq_f"); 236ad75a51eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 237c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 238c301f34eSRichard Henderson "iasq_b"); 23961766fe9SRichard Henderson } 24061766fe9SRichard Henderson 241f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg) 242f5b5c857SRichard Henderson { 243f5b5c857SRichard Henderson assert(ctx->insn_start != NULL); 244f5b5c857SRichard Henderson tcg_set_insn_start_param(ctx->insn_start, 2, breg); 245f5b5c857SRichard Henderson ctx->insn_start = NULL; 246f5b5c857SRichard Henderson } 247f5b5c857SRichard Henderson 248129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 249129e9cc3SRichard Henderson { 250f764718dSRichard Henderson return (DisasCond){ 251f764718dSRichard Henderson .c = TCG_COND_NEVER, 252f764718dSRichard Henderson .a0 = NULL, 253f764718dSRichard Henderson .a1 = NULL, 254f764718dSRichard Henderson }; 255129e9cc3SRichard Henderson } 256129e9cc3SRichard Henderson 257df0232feSRichard Henderson static DisasCond cond_make_t(void) 258df0232feSRichard Henderson { 259df0232feSRichard Henderson return (DisasCond){ 260df0232feSRichard Henderson .c = TCG_COND_ALWAYS, 261df0232feSRichard Henderson .a0 = NULL, 262df0232feSRichard Henderson .a1 = NULL, 263df0232feSRichard Henderson }; 264df0232feSRichard Henderson } 265df0232feSRichard Henderson 266129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 267129e9cc3SRichard Henderson { 268f764718dSRichard Henderson return (DisasCond){ 269f764718dSRichard Henderson .c = TCG_COND_NE, 270f764718dSRichard Henderson .a0 = cpu_psw_n, 2716fd0c7bcSRichard Henderson .a1 = tcg_constant_i64(0) 272f764718dSRichard Henderson }; 273129e9cc3SRichard Henderson } 274129e9cc3SRichard Henderson 2756fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 276b47a4a02SSven Schnelle { 277b47a4a02SSven Schnelle assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 2784fe9533aSRichard Henderson return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 2794fe9533aSRichard Henderson } 2804fe9533aSRichard Henderson 2816fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0) 2824fe9533aSRichard Henderson { 2836fd0c7bcSRichard Henderson return cond_make_tmp(c, a0, tcg_constant_i64(0)); 284b47a4a02SSven Schnelle } 285b47a4a02SSven Schnelle 2866fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0) 287129e9cc3SRichard Henderson { 288aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2896fd0c7bcSRichard Henderson tcg_gen_mov_i64(tmp, a0); 290b47a4a02SSven Schnelle return cond_make_0_tmp(c, tmp); 291129e9cc3SRichard Henderson } 292129e9cc3SRichard Henderson 2936fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 294129e9cc3SRichard Henderson { 295aac0f603SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 296aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 297129e9cc3SRichard Henderson 2986fd0c7bcSRichard Henderson tcg_gen_mov_i64(t0, a0); 2996fd0c7bcSRichard Henderson tcg_gen_mov_i64(t1, a1); 3004fe9533aSRichard Henderson return cond_make_tmp(c, t0, t1); 301129e9cc3SRichard Henderson } 302129e9cc3SRichard Henderson 303129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 304129e9cc3SRichard Henderson { 305129e9cc3SRichard Henderson switch (cond->c) { 306129e9cc3SRichard Henderson default: 307f764718dSRichard Henderson cond->a0 = NULL; 308f764718dSRichard Henderson cond->a1 = NULL; 309129e9cc3SRichard Henderson /* fallthru */ 310129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 311129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 312129e9cc3SRichard Henderson break; 313129e9cc3SRichard Henderson case TCG_COND_NEVER: 314129e9cc3SRichard Henderson break; 315129e9cc3SRichard Henderson } 316129e9cc3SRichard Henderson } 317129e9cc3SRichard Henderson 3186fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 31961766fe9SRichard Henderson { 32061766fe9SRichard Henderson if (reg == 0) { 321bc3da3cfSRichard Henderson return ctx->zero; 32261766fe9SRichard Henderson } else { 32361766fe9SRichard Henderson return cpu_gr[reg]; 32461766fe9SRichard Henderson } 32561766fe9SRichard Henderson } 32661766fe9SRichard Henderson 3276fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 32861766fe9SRichard Henderson { 329129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 330aac0f603SRichard Henderson return tcg_temp_new_i64(); 33161766fe9SRichard Henderson } else { 33261766fe9SRichard Henderson return cpu_gr[reg]; 33361766fe9SRichard Henderson } 33461766fe9SRichard Henderson } 33561766fe9SRichard Henderson 3366fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 337129e9cc3SRichard Henderson { 338129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 3396fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 340129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 341129e9cc3SRichard Henderson } else { 3426fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 343129e9cc3SRichard Henderson } 344129e9cc3SRichard Henderson } 345129e9cc3SRichard Henderson 3466fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 347129e9cc3SRichard Henderson { 348129e9cc3SRichard Henderson if (reg != 0) { 349129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 350129e9cc3SRichard Henderson } 351129e9cc3SRichard Henderson } 352129e9cc3SRichard Henderson 353e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 35496d6407fSRichard Henderson # define HI_OFS 0 35596d6407fSRichard Henderson # define LO_OFS 4 35696d6407fSRichard Henderson #else 35796d6407fSRichard Henderson # define HI_OFS 4 35896d6407fSRichard Henderson # define LO_OFS 0 35996d6407fSRichard Henderson #endif 36096d6407fSRichard Henderson 36196d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 36296d6407fSRichard Henderson { 36396d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 364ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 36596d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 36696d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 36796d6407fSRichard Henderson return ret; 36896d6407fSRichard Henderson } 36996d6407fSRichard Henderson 370ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 371ebe9383cSRichard Henderson { 372ebe9383cSRichard Henderson if (rt == 0) { 3730992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 3740992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 3750992a930SRichard Henderson return ret; 376ebe9383cSRichard Henderson } else { 377ebe9383cSRichard Henderson return load_frw_i32(rt); 378ebe9383cSRichard Henderson } 379ebe9383cSRichard Henderson } 380ebe9383cSRichard Henderson 381ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 382ebe9383cSRichard Henderson { 383ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 3840992a930SRichard Henderson if (rt == 0) { 3850992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 3860992a930SRichard Henderson } else { 387ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 388ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 389ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 390ebe9383cSRichard Henderson } 3910992a930SRichard Henderson return ret; 392ebe9383cSRichard Henderson } 393ebe9383cSRichard Henderson 39496d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 39596d6407fSRichard Henderson { 396ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 39796d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 39896d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 39996d6407fSRichard Henderson } 40096d6407fSRichard Henderson 40196d6407fSRichard Henderson #undef HI_OFS 40296d6407fSRichard Henderson #undef LO_OFS 40396d6407fSRichard Henderson 40496d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 40596d6407fSRichard Henderson { 40696d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 407ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 40896d6407fSRichard Henderson return ret; 40996d6407fSRichard Henderson } 41096d6407fSRichard Henderson 411ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 412ebe9383cSRichard Henderson { 413ebe9383cSRichard Henderson if (rt == 0) { 4140992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4150992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4160992a930SRichard Henderson return ret; 417ebe9383cSRichard Henderson } else { 418ebe9383cSRichard Henderson return load_frd(rt); 419ebe9383cSRichard Henderson } 420ebe9383cSRichard Henderson } 421ebe9383cSRichard Henderson 42296d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 42396d6407fSRichard Henderson { 424ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 42596d6407fSRichard Henderson } 42696d6407fSRichard Henderson 42733423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 42833423472SRichard Henderson { 42933423472SRichard Henderson #ifdef CONFIG_USER_ONLY 43033423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 43133423472SRichard Henderson #else 43233423472SRichard Henderson if (reg < 4) { 43333423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 434494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 435494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 43633423472SRichard Henderson } else { 437ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 43833423472SRichard Henderson } 43933423472SRichard Henderson #endif 44033423472SRichard Henderson } 44133423472SRichard Henderson 442129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 443129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 444129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 445129e9cc3SRichard Henderson { 446129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 447129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 448129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 449129e9cc3SRichard Henderson 450129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 451129e9cc3SRichard Henderson 452129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 4536e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 454aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 4556fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 456129e9cc3SRichard Henderson } 457129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 458129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 459129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 460129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 461129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 4626fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 463129e9cc3SRichard Henderson } 464129e9cc3SRichard Henderson 4656fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 466129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 467129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 468129e9cc3SRichard Henderson } 469129e9cc3SRichard Henderson } 470129e9cc3SRichard Henderson 471129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 472129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 473129e9cc3SRichard Henderson { 474129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 475129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 4766fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 477129e9cc3SRichard Henderson } 478129e9cc3SRichard Henderson return; 479129e9cc3SRichard Henderson } 4806e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 4816fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 482129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 483129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 484129e9cc3SRichard Henderson } 485129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 486129e9cc3SRichard Henderson } 487129e9cc3SRichard Henderson 488129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 489129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 490129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 491129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 492129e9cc3SRichard Henderson { 493129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 4946fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 495129e9cc3SRichard Henderson } 496129e9cc3SRichard Henderson } 497129e9cc3SRichard Henderson 498129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 49940f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 50040f9f908SRichard Henderson it may be tail-called from a translate function. */ 50131234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 502129e9cc3SRichard Henderson { 503129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 50431234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 505129e9cc3SRichard Henderson 506f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 507f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 508f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 509f49b3537SRichard Henderson 510129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 511129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 512129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 513129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 51431234768SRichard Henderson return true; 515129e9cc3SRichard Henderson } 516129e9cc3SRichard Henderson ctx->null_lab = NULL; 517129e9cc3SRichard Henderson 518129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 519129e9cc3SRichard Henderson /* The next instruction will be unconditional, 520129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 521129e9cc3SRichard Henderson gen_set_label(null_lab); 522129e9cc3SRichard Henderson } else { 523129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 524129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 525129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 526129e9cc3SRichard Henderson label we have the proper value in place. */ 527129e9cc3SRichard Henderson nullify_save(ctx); 528129e9cc3SRichard Henderson gen_set_label(null_lab); 529129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 530129e9cc3SRichard Henderson } 531869051eaSRichard Henderson if (status == DISAS_NORETURN) { 53231234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 533129e9cc3SRichard Henderson } 53431234768SRichard Henderson return true; 535129e9cc3SRichard Henderson } 536129e9cc3SRichard Henderson 537c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx) 538698240d1SRichard Henderson { 539698240d1SRichard Henderson return (ctx->tb_flags & PSW_W 540698240d1SRichard Henderson ? MAKE_64BIT_MASK(0, 62) 541698240d1SRichard Henderson : MAKE_64BIT_MASK(0, 32)); 542698240d1SRichard Henderson } 543698240d1SRichard Henderson 5446fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 5456fd0c7bcSRichard Henderson uint64_t ival, TCGv_i64 vval) 54661766fe9SRichard Henderson { 547c53e401eSRichard Henderson uint64_t mask = gva_offset_mask(ctx); 548f13bf343SRichard Henderson 549f13bf343SRichard Henderson if (ival != -1) { 5506fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, ival & mask); 551f13bf343SRichard Henderson return; 552f13bf343SRichard Henderson } 553f13bf343SRichard Henderson tcg_debug_assert(vval != NULL); 554f13bf343SRichard Henderson 555f13bf343SRichard Henderson /* 556f13bf343SRichard Henderson * We know that the IAOQ is already properly masked. 557f13bf343SRichard Henderson * This optimization is primarily for "iaoq_f = iaoq_b". 558f13bf343SRichard Henderson */ 559f13bf343SRichard Henderson if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) { 5606fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, vval); 56161766fe9SRichard Henderson } else { 5626fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, vval, mask); 56361766fe9SRichard Henderson } 56461766fe9SRichard Henderson } 56561766fe9SRichard Henderson 566c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp) 56761766fe9SRichard Henderson { 56861766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 56961766fe9SRichard Henderson } 57061766fe9SRichard Henderson 57161766fe9SRichard Henderson static void gen_excp_1(int exception) 57261766fe9SRichard Henderson { 573ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 57461766fe9SRichard Henderson } 57561766fe9SRichard Henderson 57631234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 57761766fe9SRichard Henderson { 578741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 579741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 580129e9cc3SRichard Henderson nullify_save(ctx); 58161766fe9SRichard Henderson gen_excp_1(exception); 58231234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 58361766fe9SRichard Henderson } 58461766fe9SRichard Henderson 58531234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 5861a19da0dSRichard Henderson { 58731234768SRichard Henderson nullify_over(ctx); 5886fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 589ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 59031234768SRichard Henderson gen_excp(ctx, exc); 59131234768SRichard Henderson return nullify_end(ctx); 5921a19da0dSRichard Henderson } 5931a19da0dSRichard Henderson 59431234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 59561766fe9SRichard Henderson { 59631234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 59761766fe9SRichard Henderson } 59861766fe9SRichard Henderson 59940f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 60040f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 60140f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 60240f9f908SRichard Henderson #else 603e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 604e1b5a5edSRichard Henderson do { \ 605e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 60631234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 607e1b5a5edSRichard Henderson } \ 608e1b5a5edSRichard Henderson } while (0) 60940f9f908SRichard Henderson #endif 610e1b5a5edSRichard Henderson 611c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest) 61261766fe9SRichard Henderson { 61357f91498SRichard Henderson return translator_use_goto_tb(&ctx->base, dest); 61461766fe9SRichard Henderson } 61561766fe9SRichard Henderson 616129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 617129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 618129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 619129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 620129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 621129e9cc3SRichard Henderson { 622129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 623129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 624129e9cc3SRichard Henderson } 625129e9cc3SRichard Henderson 62661766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 627c53e401eSRichard Henderson uint64_t f, uint64_t b) 62861766fe9SRichard Henderson { 62961766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 63061766fe9SRichard Henderson tcg_gen_goto_tb(which); 631a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL); 632a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL); 63307ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 63461766fe9SRichard Henderson } else { 635741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b); 636741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var); 6377f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 63861766fe9SRichard Henderson } 63961766fe9SRichard Henderson } 64061766fe9SRichard Henderson 641b47a4a02SSven Schnelle static bool cond_need_sv(int c) 642b47a4a02SSven Schnelle { 643b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 644b47a4a02SSven Schnelle } 645b47a4a02SSven Schnelle 646b47a4a02SSven Schnelle static bool cond_need_cb(int c) 647b47a4a02SSven Schnelle { 648b47a4a02SSven Schnelle return c == 4 || c == 5; 649b47a4a02SSven Schnelle } 650b47a4a02SSven Schnelle 6516fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */ 65272ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d) 65372ca8753SRichard Henderson { 654c53e401eSRichard Henderson return !(ctx->is_pa20 && d); 65572ca8753SRichard Henderson } 65672ca8753SRichard Henderson 657b47a4a02SSven Schnelle /* 658b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 659b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 660b47a4a02SSven Schnelle */ 661b2167459SRichard Henderson 662a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 6636fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv) 664b2167459SRichard Henderson { 665b2167459SRichard Henderson DisasCond cond; 6666fd0c7bcSRichard Henderson TCGv_i64 tmp; 667b2167459SRichard Henderson 668b2167459SRichard Henderson switch (cf >> 1) { 669b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 670b2167459SRichard Henderson cond = cond_make_f(); 671b2167459SRichard Henderson break; 672b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 673a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 674aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6756fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 676a751eb31SRichard Henderson res = tmp; 677a751eb31SRichard Henderson } 678b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 679b2167459SRichard Henderson break; 680b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 681aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6826fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 683a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 6846fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, tmp); 685a751eb31SRichard Henderson } 686b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_LT, tmp); 687b2167459SRichard Henderson break; 688b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 689b47a4a02SSven Schnelle /* 690b47a4a02SSven Schnelle * Simplify: 691b47a4a02SSven Schnelle * (N ^ V) | Z 692b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 693b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 694b47a4a02SSven Schnelle * (~(res ^ sv) >= 0) | !res 695b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31) | !res 696b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31 & res) 697b47a4a02SSven Schnelle */ 698aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6996fd0c7bcSRichard Henderson tcg_gen_eqv_i64(tmp, res, sv); 700a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7016fd0c7bcSRichard Henderson tcg_gen_sextract_i64(tmp, tmp, 31, 1); 7026fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 7036fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 704a751eb31SRichard Henderson } else { 7056fd0c7bcSRichard Henderson tcg_gen_sari_i64(tmp, tmp, 63); 7066fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 707a751eb31SRichard Henderson } 708b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 709b2167459SRichard Henderson break; 710b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 711a751eb31SRichard Henderson /* Only bit 0 of cb_msb is ever set. */ 712b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 713b2167459SRichard Henderson break; 714b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 715aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7166fd0c7bcSRichard Henderson tcg_gen_neg_i64(tmp, cb_msb); 7176fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 718a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7196fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 720a751eb31SRichard Henderson } 721b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 722b2167459SRichard Henderson break; 723b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 724a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 725aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7266fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, sv); 727a751eb31SRichard Henderson sv = tmp; 728a751eb31SRichard Henderson } 729b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 730b2167459SRichard Henderson break; 731b2167459SRichard Henderson case 7: /* OD / EV */ 732aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7336fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, res, 1); 734b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_NE, tmp); 735b2167459SRichard Henderson break; 736b2167459SRichard Henderson default: 737b2167459SRichard Henderson g_assert_not_reached(); 738b2167459SRichard Henderson } 739b2167459SRichard Henderson if (cf & 1) { 740b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 741b2167459SRichard Henderson } 742b2167459SRichard Henderson 743b2167459SRichard Henderson return cond; 744b2167459SRichard Henderson } 745b2167459SRichard Henderson 746b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 747b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 748b2167459SRichard Henderson deleted as unused. */ 749b2167459SRichard Henderson 7504fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 7516fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 7526fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 753b2167459SRichard Henderson { 7544fe9533aSRichard Henderson TCGCond tc; 7554fe9533aSRichard Henderson bool ext_uns; 756b2167459SRichard Henderson 757b2167459SRichard Henderson switch (cf >> 1) { 758b2167459SRichard Henderson case 1: /* = / <> */ 7594fe9533aSRichard Henderson tc = TCG_COND_EQ; 7604fe9533aSRichard Henderson ext_uns = true; 761b2167459SRichard Henderson break; 762b2167459SRichard Henderson case 2: /* < / >= */ 7634fe9533aSRichard Henderson tc = TCG_COND_LT; 7644fe9533aSRichard Henderson ext_uns = false; 765b2167459SRichard Henderson break; 766b2167459SRichard Henderson case 3: /* <= / > */ 7674fe9533aSRichard Henderson tc = TCG_COND_LE; 7684fe9533aSRichard Henderson ext_uns = false; 769b2167459SRichard Henderson break; 770b2167459SRichard Henderson case 4: /* << / >>= */ 7714fe9533aSRichard Henderson tc = TCG_COND_LTU; 7724fe9533aSRichard Henderson ext_uns = true; 773b2167459SRichard Henderson break; 774b2167459SRichard Henderson case 5: /* <<= / >> */ 7754fe9533aSRichard Henderson tc = TCG_COND_LEU; 7764fe9533aSRichard Henderson ext_uns = true; 777b2167459SRichard Henderson break; 778b2167459SRichard Henderson default: 779a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 780b2167459SRichard Henderson } 781b2167459SRichard Henderson 7824fe9533aSRichard Henderson if (cf & 1) { 7834fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 7844fe9533aSRichard Henderson } 7854fe9533aSRichard Henderson if (cond_need_ext(ctx, d)) { 786aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 787aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 7884fe9533aSRichard Henderson 7894fe9533aSRichard Henderson if (ext_uns) { 7906fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 7916fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 7924fe9533aSRichard Henderson } else { 7936fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 7946fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 7954fe9533aSRichard Henderson } 7964fe9533aSRichard Henderson return cond_make_tmp(tc, t1, t2); 7974fe9533aSRichard Henderson } 7984fe9533aSRichard Henderson return cond_make(tc, in1, in2); 799b2167459SRichard Henderson } 800b2167459SRichard Henderson 801df0232feSRichard Henderson /* 802df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 803df0232feSRichard Henderson * computed, and use of them is undefined. 804df0232feSRichard Henderson * 805df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 806df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 807df0232feSRichard Henderson * how cases c={2,3} are treated. 808df0232feSRichard Henderson */ 809b2167459SRichard Henderson 810b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 8116fd0c7bcSRichard Henderson TCGv_i64 res) 812b2167459SRichard Henderson { 813b5af8423SRichard Henderson TCGCond tc; 814b5af8423SRichard Henderson bool ext_uns; 815a751eb31SRichard Henderson 816df0232feSRichard Henderson switch (cf) { 817df0232feSRichard Henderson case 0: /* never */ 818df0232feSRichard Henderson case 9: /* undef, C */ 819df0232feSRichard Henderson case 11: /* undef, C & !Z */ 820df0232feSRichard Henderson case 12: /* undef, V */ 821df0232feSRichard Henderson return cond_make_f(); 822df0232feSRichard Henderson 823df0232feSRichard Henderson case 1: /* true */ 824df0232feSRichard Henderson case 8: /* undef, !C */ 825df0232feSRichard Henderson case 10: /* undef, !C | Z */ 826df0232feSRichard Henderson case 13: /* undef, !V */ 827df0232feSRichard Henderson return cond_make_t(); 828df0232feSRichard Henderson 829df0232feSRichard Henderson case 2: /* == */ 830b5af8423SRichard Henderson tc = TCG_COND_EQ; 831b5af8423SRichard Henderson ext_uns = true; 832b5af8423SRichard Henderson break; 833df0232feSRichard Henderson case 3: /* <> */ 834b5af8423SRichard Henderson tc = TCG_COND_NE; 835b5af8423SRichard Henderson ext_uns = true; 836b5af8423SRichard Henderson break; 837df0232feSRichard Henderson case 4: /* < */ 838b5af8423SRichard Henderson tc = TCG_COND_LT; 839b5af8423SRichard Henderson ext_uns = false; 840b5af8423SRichard Henderson break; 841df0232feSRichard Henderson case 5: /* >= */ 842b5af8423SRichard Henderson tc = TCG_COND_GE; 843b5af8423SRichard Henderson ext_uns = false; 844b5af8423SRichard Henderson break; 845df0232feSRichard Henderson case 6: /* <= */ 846b5af8423SRichard Henderson tc = TCG_COND_LE; 847b5af8423SRichard Henderson ext_uns = false; 848b5af8423SRichard Henderson break; 849df0232feSRichard Henderson case 7: /* > */ 850b5af8423SRichard Henderson tc = TCG_COND_GT; 851b5af8423SRichard Henderson ext_uns = false; 852b5af8423SRichard Henderson break; 853df0232feSRichard Henderson 854df0232feSRichard Henderson case 14: /* OD */ 855df0232feSRichard Henderson case 15: /* EV */ 856a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, NULL); 857df0232feSRichard Henderson 858df0232feSRichard Henderson default: 859df0232feSRichard Henderson g_assert_not_reached(); 860b2167459SRichard Henderson } 861b5af8423SRichard Henderson 862b5af8423SRichard Henderson if (cond_need_ext(ctx, d)) { 863aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 864b5af8423SRichard Henderson 865b5af8423SRichard Henderson if (ext_uns) { 8666fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 867b5af8423SRichard Henderson } else { 8686fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 869b5af8423SRichard Henderson } 870b5af8423SRichard Henderson return cond_make_0_tmp(tc, tmp); 871b5af8423SRichard Henderson } 872b5af8423SRichard Henderson return cond_make_0(tc, res); 873b2167459SRichard Henderson } 874b2167459SRichard Henderson 87598cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 87698cd9ca7SRichard Henderson 8774fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 8786fd0c7bcSRichard Henderson TCGv_i64 res) 87998cd9ca7SRichard Henderson { 88098cd9ca7SRichard Henderson unsigned c, f; 88198cd9ca7SRichard Henderson 88298cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 88398cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 88498cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 88598cd9ca7SRichard Henderson c = orig & 3; 88698cd9ca7SRichard Henderson if (c == 3) { 88798cd9ca7SRichard Henderson c = 7; 88898cd9ca7SRichard Henderson } 88998cd9ca7SRichard Henderson f = (orig & 4) / 4; 89098cd9ca7SRichard Henderson 891b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 89298cd9ca7SRichard Henderson } 89398cd9ca7SRichard Henderson 894b2167459SRichard Henderson /* Similar, but for unit conditions. */ 895b2167459SRichard Henderson 8966fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res, 8976fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 898b2167459SRichard Henderson { 899b2167459SRichard Henderson DisasCond cond; 9006fd0c7bcSRichard Henderson TCGv_i64 tmp, cb = NULL; 901c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 902b2167459SRichard Henderson 903b2167459SRichard Henderson if (cf & 8) { 904b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 905b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 906b2167459SRichard Henderson * leaves us with carry bits spread across two words. 907b2167459SRichard Henderson */ 908aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 909aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9106fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, in1, in2); 9116fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, in1, in2); 9126fd0c7bcSRichard Henderson tcg_gen_andc_i64(cb, cb, res); 9136fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, cb, tmp); 914b2167459SRichard Henderson } 915b2167459SRichard Henderson 916b2167459SRichard Henderson switch (cf >> 1) { 917b2167459SRichard Henderson case 0: /* never / TR */ 918b2167459SRichard Henderson case 1: /* undefined */ 919b2167459SRichard Henderson case 5: /* undefined */ 920b2167459SRichard Henderson cond = cond_make_f(); 921b2167459SRichard Henderson break; 922b2167459SRichard Henderson 923b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 924b2167459SRichard Henderson /* See hasless(v,1) from 925b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 926b2167459SRichard Henderson */ 927aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9286fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u); 9296fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9306fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u); 931b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 932b2167459SRichard Henderson break; 933b2167459SRichard Henderson 934b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 935aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9366fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u); 9376fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9386fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u); 939b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 940b2167459SRichard Henderson break; 941b2167459SRichard Henderson 942b2167459SRichard Henderson case 4: /* SDC / NDC */ 9436fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u); 944b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 945b2167459SRichard Henderson break; 946b2167459SRichard Henderson 947b2167459SRichard Henderson case 6: /* SBC / NBC */ 9486fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u); 949b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 950b2167459SRichard Henderson break; 951b2167459SRichard Henderson 952b2167459SRichard Henderson case 7: /* SHC / NHC */ 9536fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u); 954b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 955b2167459SRichard Henderson break; 956b2167459SRichard Henderson 957b2167459SRichard Henderson default: 958b2167459SRichard Henderson g_assert_not_reached(); 959b2167459SRichard Henderson } 960b2167459SRichard Henderson if (cf & 1) { 961b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 962b2167459SRichard Henderson } 963b2167459SRichard Henderson 964b2167459SRichard Henderson return cond; 965b2167459SRichard Henderson } 966b2167459SRichard Henderson 9676fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 9686fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 96972ca8753SRichard Henderson { 97072ca8753SRichard Henderson if (cond_need_ext(ctx, d)) { 971aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 9726fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 97372ca8753SRichard Henderson return t; 97472ca8753SRichard Henderson } 97572ca8753SRichard Henderson return cb_msb; 97672ca8753SRichard Henderson } 97772ca8753SRichard Henderson 9786fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 97972ca8753SRichard Henderson { 98072ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 98172ca8753SRichard Henderson } 98272ca8753SRichard Henderson 983b2167459SRichard Henderson /* Compute signed overflow for addition. */ 9846fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 9856fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 986b2167459SRichard Henderson { 987aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 988aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 989b2167459SRichard Henderson 9906fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 9916fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 9926fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 993b2167459SRichard Henderson 994b2167459SRichard Henderson return sv; 995b2167459SRichard Henderson } 996b2167459SRichard Henderson 997b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 9986fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 9996fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1000b2167459SRichard Henderson { 1001aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1002aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1003b2167459SRichard Henderson 10046fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10056fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10066fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 1007b2167459SRichard Henderson 1008b2167459SRichard Henderson return sv; 1009b2167459SRichard Henderson } 1010b2167459SRichard Henderson 10116fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 10126fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1013faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1014b2167459SRichard Henderson { 10156fd0c7bcSRichard Henderson TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp; 1016b2167459SRichard Henderson unsigned c = cf >> 1; 1017b2167459SRichard Henderson DisasCond cond; 1018b2167459SRichard Henderson 1019aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1020f764718dSRichard Henderson cb = NULL; 1021f764718dSRichard Henderson cb_msb = NULL; 1022bdcccc17SRichard Henderson cb_cond = NULL; 1023b2167459SRichard Henderson 1024b2167459SRichard Henderson if (shift) { 1025aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10266fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1027b2167459SRichard Henderson in1 = tmp; 1028b2167459SRichard Henderson } 1029b2167459SRichard Henderson 1030b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1031aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1032aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1033bdcccc17SRichard Henderson 1034a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1035b2167459SRichard Henderson if (is_c) { 10366fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1037a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1038b2167459SRichard Henderson } 10396fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 10406fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1041bdcccc17SRichard Henderson if (cond_need_cb(c)) { 1042bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 1043b2167459SRichard Henderson } 1044b2167459SRichard Henderson } else { 10456fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1046b2167459SRichard Henderson if (is_c) { 10476fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1048b2167459SRichard Henderson } 1049b2167459SRichard Henderson } 1050b2167459SRichard Henderson 1051b2167459SRichard Henderson /* Compute signed overflow if required. */ 1052f764718dSRichard Henderson sv = NULL; 1053b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1054b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 1055b2167459SRichard Henderson if (is_tsv) { 1056b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 1057ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1058b2167459SRichard Henderson } 1059b2167459SRichard Henderson } 1060b2167459SRichard Henderson 1061b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1062a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, cb_cond, sv); 1063b2167459SRichard Henderson if (is_tc) { 1064aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10656fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1066ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1067b2167459SRichard Henderson } 1068b2167459SRichard Henderson 1069b2167459SRichard Henderson /* Write back the result. */ 1070b2167459SRichard Henderson if (!is_l) { 1071b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1072b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1073b2167459SRichard Henderson } 1074b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1075b2167459SRichard Henderson 1076b2167459SRichard Henderson /* Install the new nullification. */ 1077b2167459SRichard Henderson cond_free(&ctx->null_cond); 1078b2167459SRichard Henderson ctx->null_cond = cond; 1079b2167459SRichard Henderson } 1080b2167459SRichard Henderson 1081faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 10820c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 10830c982a28SRichard Henderson { 10846fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 10850c982a28SRichard Henderson 10860c982a28SRichard Henderson if (a->cf) { 10870c982a28SRichard Henderson nullify_over(ctx); 10880c982a28SRichard Henderson } 10890c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 10900c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1091faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1092faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 10930c982a28SRichard Henderson return nullify_end(ctx); 10940c982a28SRichard Henderson } 10950c982a28SRichard Henderson 10960588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 10970588e061SRichard Henderson bool is_tsv, bool is_tc) 10980588e061SRichard Henderson { 10996fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11000588e061SRichard Henderson 11010588e061SRichard Henderson if (a->cf) { 11020588e061SRichard Henderson nullify_over(ctx); 11030588e061SRichard Henderson } 11046fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11050588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1106faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1107faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 11080588e061SRichard Henderson return nullify_end(ctx); 11090588e061SRichard Henderson } 11100588e061SRichard Henderson 11116fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 11126fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 111363c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1114b2167459SRichard Henderson { 1115a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1116b2167459SRichard Henderson unsigned c = cf >> 1; 1117b2167459SRichard Henderson DisasCond cond; 1118b2167459SRichard Henderson 1119aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1120aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1121aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1122b2167459SRichard Henderson 1123b2167459SRichard Henderson if (is_b) { 1124b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 11256fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1126a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1127a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1128a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 11296fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 11306fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1131b2167459SRichard Henderson } else { 1132bdcccc17SRichard Henderson /* 1133bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1134bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1135bdcccc17SRichard Henderson */ 11366fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1137a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 11386fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 11396fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1140b2167459SRichard Henderson } 1141b2167459SRichard Henderson 1142b2167459SRichard Henderson /* Compute signed overflow if required. */ 1143f764718dSRichard Henderson sv = NULL; 1144b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1145b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1146b2167459SRichard Henderson if (is_tsv) { 1147ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1148b2167459SRichard Henderson } 1149b2167459SRichard Henderson } 1150b2167459SRichard Henderson 1151b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1152b2167459SRichard Henderson if (!is_b) { 11534fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1154b2167459SRichard Henderson } else { 1155a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1156b2167459SRichard Henderson } 1157b2167459SRichard Henderson 1158b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1159b2167459SRichard Henderson if (is_tc) { 1160aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11616fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1162ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1163b2167459SRichard Henderson } 1164b2167459SRichard Henderson 1165b2167459SRichard Henderson /* Write back the result. */ 1166b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1167b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1168b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1169b2167459SRichard Henderson 1170b2167459SRichard Henderson /* Install the new nullification. */ 1171b2167459SRichard Henderson cond_free(&ctx->null_cond); 1172b2167459SRichard Henderson ctx->null_cond = cond; 1173b2167459SRichard Henderson } 1174b2167459SRichard Henderson 117563c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 11760c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 11770c982a28SRichard Henderson { 11786fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 11790c982a28SRichard Henderson 11800c982a28SRichard Henderson if (a->cf) { 11810c982a28SRichard Henderson nullify_over(ctx); 11820c982a28SRichard Henderson } 11830c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 11840c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 118563c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 11860c982a28SRichard Henderson return nullify_end(ctx); 11870c982a28SRichard Henderson } 11880c982a28SRichard Henderson 11890588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 11900588e061SRichard Henderson { 11916fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11920588e061SRichard Henderson 11930588e061SRichard Henderson if (a->cf) { 11940588e061SRichard Henderson nullify_over(ctx); 11950588e061SRichard Henderson } 11966fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11970588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 119863c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 119963c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 12000588e061SRichard Henderson return nullify_end(ctx); 12010588e061SRichard Henderson } 12020588e061SRichard Henderson 12036fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12046fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1205b2167459SRichard Henderson { 12066fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1207b2167459SRichard Henderson DisasCond cond; 1208b2167459SRichard Henderson 1209aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 12106fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1211b2167459SRichard Henderson 1212b2167459SRichard Henderson /* Compute signed overflow if required. */ 1213f764718dSRichard Henderson sv = NULL; 1214b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1215b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1216b2167459SRichard Henderson } 1217b2167459SRichard Henderson 1218b2167459SRichard Henderson /* Form the condition for the compare. */ 12194fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1220b2167459SRichard Henderson 1221b2167459SRichard Henderson /* Clear. */ 12226fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1223b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1224b2167459SRichard Henderson 1225b2167459SRichard Henderson /* Install the new nullification. */ 1226b2167459SRichard Henderson cond_free(&ctx->null_cond); 1227b2167459SRichard Henderson ctx->null_cond = cond; 1228b2167459SRichard Henderson } 1229b2167459SRichard Henderson 12306fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12316fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 12326fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1233b2167459SRichard Henderson { 12346fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1235b2167459SRichard Henderson 1236b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1237b2167459SRichard Henderson fn(dest, in1, in2); 1238b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1239b2167459SRichard Henderson 1240b2167459SRichard Henderson /* Install the new nullification. */ 1241b2167459SRichard Henderson cond_free(&ctx->null_cond); 1242b2167459SRichard Henderson if (cf) { 1243b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1244b2167459SRichard Henderson } 1245b2167459SRichard Henderson } 1246b2167459SRichard Henderson 1247fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12486fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 12490c982a28SRichard Henderson { 12506fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12510c982a28SRichard Henderson 12520c982a28SRichard Henderson if (a->cf) { 12530c982a28SRichard Henderson nullify_over(ctx); 12540c982a28SRichard Henderson } 12550c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12560c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1257fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 12580c982a28SRichard Henderson return nullify_end(ctx); 12590c982a28SRichard Henderson } 12600c982a28SRichard Henderson 12616fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12626fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, bool is_tc, 12636fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1264b2167459SRichard Henderson { 12656fd0c7bcSRichard Henderson TCGv_i64 dest; 1266b2167459SRichard Henderson DisasCond cond; 1267b2167459SRichard Henderson 1268b2167459SRichard Henderson if (cf == 0) { 1269b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 1270b2167459SRichard Henderson fn(dest, in1, in2); 1271b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1272b2167459SRichard Henderson cond_free(&ctx->null_cond); 1273b2167459SRichard Henderson } else { 1274aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1275b2167459SRichard Henderson fn(dest, in1, in2); 1276b2167459SRichard Henderson 127759963d8fSRichard Henderson cond = do_unit_cond(cf, d, dest, in1, in2); 1278b2167459SRichard Henderson 1279b2167459SRichard Henderson if (is_tc) { 1280aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 12816fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1282ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1283b2167459SRichard Henderson } 1284b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1285b2167459SRichard Henderson 1286b2167459SRichard Henderson cond_free(&ctx->null_cond); 1287b2167459SRichard Henderson ctx->null_cond = cond; 1288b2167459SRichard Henderson } 1289b2167459SRichard Henderson } 1290b2167459SRichard Henderson 129186f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 12928d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 12938d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 12948d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 12958d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 12966fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 129786f8d05fSRichard Henderson { 129886f8d05fSRichard Henderson TCGv_ptr ptr; 12996fd0c7bcSRichard Henderson TCGv_i64 tmp; 130086f8d05fSRichard Henderson TCGv_i64 spc; 130186f8d05fSRichard Henderson 130286f8d05fSRichard Henderson if (sp != 0) { 13038d6ae7fbSRichard Henderson if (sp < 0) { 13048d6ae7fbSRichard Henderson sp = ~sp; 13058d6ae7fbSRichard Henderson } 13066fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 13078d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 13088d6ae7fbSRichard Henderson return spc; 130986f8d05fSRichard Henderson } 1310494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1311494737b7SRichard Henderson return cpu_srH; 1312494737b7SRichard Henderson } 131386f8d05fSRichard Henderson 131486f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1315aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 13166fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 131786f8d05fSRichard Henderson 1318698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 13196fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 13206fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 13216fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 132286f8d05fSRichard Henderson 1323ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 132486f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 132586f8d05fSRichard Henderson 132686f8d05fSRichard Henderson return spc; 132786f8d05fSRichard Henderson } 132886f8d05fSRichard Henderson #endif 132986f8d05fSRichard Henderson 13306fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1331c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 133286f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 133386f8d05fSRichard Henderson { 13346fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 13356fd0c7bcSRichard Henderson TCGv_i64 ofs; 13366fd0c7bcSRichard Henderson TCGv_i64 addr; 133786f8d05fSRichard Henderson 1338f5b5c857SRichard Henderson set_insn_breg(ctx, rb); 1339f5b5c857SRichard Henderson 134086f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 134186f8d05fSRichard Henderson if (rx) { 1342aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13436fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 13446fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 134586f8d05fSRichard Henderson } else if (disp || modify) { 1346aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13476fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 134886f8d05fSRichard Henderson } else { 134986f8d05fSRichard Henderson ofs = base; 135086f8d05fSRichard Henderson } 135186f8d05fSRichard Henderson 135286f8d05fSRichard Henderson *pofs = ofs; 13536fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 1354d265360fSRichard Henderson tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx)); 1355698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 135686f8d05fSRichard Henderson if (!is_phys) { 1357d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 135886f8d05fSRichard Henderson } 135986f8d05fSRichard Henderson #endif 136086f8d05fSRichard Henderson } 136186f8d05fSRichard Henderson 136296d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 136396d6407fSRichard Henderson * < 0 for pre-modify, 136496d6407fSRichard Henderson * > 0 for post-modify, 136596d6407fSRichard Henderson * = 0 for no base register update. 136696d6407fSRichard Henderson */ 136796d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1368c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 136914776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 137096d6407fSRichard Henderson { 13716fd0c7bcSRichard Henderson TCGv_i64 ofs; 13726fd0c7bcSRichard Henderson TCGv_i64 addr; 137396d6407fSRichard Henderson 137496d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 137596d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 137696d6407fSRichard Henderson 137786f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 137886f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1379c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 138086f8d05fSRichard Henderson if (modify) { 138186f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 138296d6407fSRichard Henderson } 138396d6407fSRichard Henderson } 138496d6407fSRichard Henderson 138596d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1386c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 138714776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 138896d6407fSRichard Henderson { 13896fd0c7bcSRichard Henderson TCGv_i64 ofs; 13906fd0c7bcSRichard Henderson TCGv_i64 addr; 139196d6407fSRichard Henderson 139296d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 139396d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 139496d6407fSRichard Henderson 139586f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 139686f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1397217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 139886f8d05fSRichard Henderson if (modify) { 139986f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 140096d6407fSRichard Henderson } 140196d6407fSRichard Henderson } 140296d6407fSRichard Henderson 140396d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1404c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 140514776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 140696d6407fSRichard Henderson { 14076fd0c7bcSRichard Henderson TCGv_i64 ofs; 14086fd0c7bcSRichard Henderson TCGv_i64 addr; 140996d6407fSRichard Henderson 141096d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 141196d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 141296d6407fSRichard Henderson 141386f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 141486f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1415217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 141686f8d05fSRichard Henderson if (modify) { 141786f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 141896d6407fSRichard Henderson } 141996d6407fSRichard Henderson } 142096d6407fSRichard Henderson 142196d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1422c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 142314776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 142496d6407fSRichard Henderson { 14256fd0c7bcSRichard Henderson TCGv_i64 ofs; 14266fd0c7bcSRichard Henderson TCGv_i64 addr; 142796d6407fSRichard Henderson 142896d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 142996d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 143096d6407fSRichard Henderson 143186f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 143286f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1433217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 143486f8d05fSRichard Henderson if (modify) { 143586f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 143696d6407fSRichard Henderson } 143796d6407fSRichard Henderson } 143896d6407fSRichard Henderson 14391cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1440c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 144114776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 144296d6407fSRichard Henderson { 14436fd0c7bcSRichard Henderson TCGv_i64 dest; 144496d6407fSRichard Henderson 144596d6407fSRichard Henderson nullify_over(ctx); 144696d6407fSRichard Henderson 144796d6407fSRichard Henderson if (modify == 0) { 144896d6407fSRichard Henderson /* No base register update. */ 144996d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 145096d6407fSRichard Henderson } else { 145196d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1452aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 145396d6407fSRichard Henderson } 14546fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 145596d6407fSRichard Henderson save_gpr(ctx, rt, dest); 145696d6407fSRichard Henderson 14571cd012a5SRichard Henderson return nullify_end(ctx); 145896d6407fSRichard Henderson } 145996d6407fSRichard Henderson 1460740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1461c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 146286f8d05fSRichard Henderson unsigned sp, int modify) 146396d6407fSRichard Henderson { 146496d6407fSRichard Henderson TCGv_i32 tmp; 146596d6407fSRichard Henderson 146696d6407fSRichard Henderson nullify_over(ctx); 146796d6407fSRichard Henderson 146896d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 146986f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 147096d6407fSRichard Henderson save_frw_i32(rt, tmp); 147196d6407fSRichard Henderson 147296d6407fSRichard Henderson if (rt == 0) { 1473ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 147496d6407fSRichard Henderson } 147596d6407fSRichard Henderson 1476740038d7SRichard Henderson return nullify_end(ctx); 147796d6407fSRichard Henderson } 147896d6407fSRichard Henderson 1479740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1480740038d7SRichard Henderson { 1481740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1482740038d7SRichard Henderson a->disp, a->sp, a->m); 1483740038d7SRichard Henderson } 1484740038d7SRichard Henderson 1485740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1486c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 148786f8d05fSRichard Henderson unsigned sp, int modify) 148896d6407fSRichard Henderson { 148996d6407fSRichard Henderson TCGv_i64 tmp; 149096d6407fSRichard Henderson 149196d6407fSRichard Henderson nullify_over(ctx); 149296d6407fSRichard Henderson 149396d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1494fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 149596d6407fSRichard Henderson save_frd(rt, tmp); 149696d6407fSRichard Henderson 149796d6407fSRichard Henderson if (rt == 0) { 1498ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 149996d6407fSRichard Henderson } 150096d6407fSRichard Henderson 1501740038d7SRichard Henderson return nullify_end(ctx); 1502740038d7SRichard Henderson } 1503740038d7SRichard Henderson 1504740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1505740038d7SRichard Henderson { 1506740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1507740038d7SRichard Henderson a->disp, a->sp, a->m); 150896d6407fSRichard Henderson } 150996d6407fSRichard Henderson 15101cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1511c53e401eSRichard Henderson int64_t disp, unsigned sp, 151214776ab5STony Nguyen int modify, MemOp mop) 151396d6407fSRichard Henderson { 151496d6407fSRichard Henderson nullify_over(ctx); 15156fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 15161cd012a5SRichard Henderson return nullify_end(ctx); 151796d6407fSRichard Henderson } 151896d6407fSRichard Henderson 1519740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1520c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 152186f8d05fSRichard Henderson unsigned sp, int modify) 152296d6407fSRichard Henderson { 152396d6407fSRichard Henderson TCGv_i32 tmp; 152496d6407fSRichard Henderson 152596d6407fSRichard Henderson nullify_over(ctx); 152696d6407fSRichard Henderson 152796d6407fSRichard Henderson tmp = load_frw_i32(rt); 152886f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 152996d6407fSRichard Henderson 1530740038d7SRichard Henderson return nullify_end(ctx); 153196d6407fSRichard Henderson } 153296d6407fSRichard Henderson 1533740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1534740038d7SRichard Henderson { 1535740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1536740038d7SRichard Henderson a->disp, a->sp, a->m); 1537740038d7SRichard Henderson } 1538740038d7SRichard Henderson 1539740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1540c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 154186f8d05fSRichard Henderson unsigned sp, int modify) 154296d6407fSRichard Henderson { 154396d6407fSRichard Henderson TCGv_i64 tmp; 154496d6407fSRichard Henderson 154596d6407fSRichard Henderson nullify_over(ctx); 154696d6407fSRichard Henderson 154796d6407fSRichard Henderson tmp = load_frd(rt); 1548fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 154996d6407fSRichard Henderson 1550740038d7SRichard Henderson return nullify_end(ctx); 1551740038d7SRichard Henderson } 1552740038d7SRichard Henderson 1553740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1554740038d7SRichard Henderson { 1555740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1556740038d7SRichard Henderson a->disp, a->sp, a->m); 155796d6407fSRichard Henderson } 155896d6407fSRichard Henderson 15591ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1560ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1561ebe9383cSRichard Henderson { 1562ebe9383cSRichard Henderson TCGv_i32 tmp; 1563ebe9383cSRichard Henderson 1564ebe9383cSRichard Henderson nullify_over(ctx); 1565ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1566ebe9383cSRichard Henderson 1567ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1568ebe9383cSRichard Henderson 1569ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 15701ca74648SRichard Henderson return nullify_end(ctx); 1571ebe9383cSRichard Henderson } 1572ebe9383cSRichard Henderson 15731ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1574ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1575ebe9383cSRichard Henderson { 1576ebe9383cSRichard Henderson TCGv_i32 dst; 1577ebe9383cSRichard Henderson TCGv_i64 src; 1578ebe9383cSRichard Henderson 1579ebe9383cSRichard Henderson nullify_over(ctx); 1580ebe9383cSRichard Henderson src = load_frd(ra); 1581ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1582ebe9383cSRichard Henderson 1583ad75a51eSRichard Henderson func(dst, tcg_env, src); 1584ebe9383cSRichard Henderson 1585ebe9383cSRichard Henderson save_frw_i32(rt, dst); 15861ca74648SRichard Henderson return nullify_end(ctx); 1587ebe9383cSRichard Henderson } 1588ebe9383cSRichard Henderson 15891ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1590ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1591ebe9383cSRichard Henderson { 1592ebe9383cSRichard Henderson TCGv_i64 tmp; 1593ebe9383cSRichard Henderson 1594ebe9383cSRichard Henderson nullify_over(ctx); 1595ebe9383cSRichard Henderson tmp = load_frd0(ra); 1596ebe9383cSRichard Henderson 1597ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1598ebe9383cSRichard Henderson 1599ebe9383cSRichard Henderson save_frd(rt, tmp); 16001ca74648SRichard Henderson return nullify_end(ctx); 1601ebe9383cSRichard Henderson } 1602ebe9383cSRichard Henderson 16031ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1604ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1605ebe9383cSRichard Henderson { 1606ebe9383cSRichard Henderson TCGv_i32 src; 1607ebe9383cSRichard Henderson TCGv_i64 dst; 1608ebe9383cSRichard Henderson 1609ebe9383cSRichard Henderson nullify_over(ctx); 1610ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1611ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1612ebe9383cSRichard Henderson 1613ad75a51eSRichard Henderson func(dst, tcg_env, src); 1614ebe9383cSRichard Henderson 1615ebe9383cSRichard Henderson save_frd(rt, dst); 16161ca74648SRichard Henderson return nullify_end(ctx); 1617ebe9383cSRichard Henderson } 1618ebe9383cSRichard Henderson 16191ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1620ebe9383cSRichard Henderson unsigned ra, unsigned rb, 162131234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1622ebe9383cSRichard Henderson { 1623ebe9383cSRichard Henderson TCGv_i32 a, b; 1624ebe9383cSRichard Henderson 1625ebe9383cSRichard Henderson nullify_over(ctx); 1626ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1627ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1628ebe9383cSRichard Henderson 1629ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1630ebe9383cSRichard Henderson 1631ebe9383cSRichard Henderson save_frw_i32(rt, a); 16321ca74648SRichard Henderson return nullify_end(ctx); 1633ebe9383cSRichard Henderson } 1634ebe9383cSRichard Henderson 16351ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1636ebe9383cSRichard Henderson unsigned ra, unsigned rb, 163731234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1638ebe9383cSRichard Henderson { 1639ebe9383cSRichard Henderson TCGv_i64 a, b; 1640ebe9383cSRichard Henderson 1641ebe9383cSRichard Henderson nullify_over(ctx); 1642ebe9383cSRichard Henderson a = load_frd0(ra); 1643ebe9383cSRichard Henderson b = load_frd0(rb); 1644ebe9383cSRichard Henderson 1645ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1646ebe9383cSRichard Henderson 1647ebe9383cSRichard Henderson save_frd(rt, a); 16481ca74648SRichard Henderson return nullify_end(ctx); 1649ebe9383cSRichard Henderson } 1650ebe9383cSRichard Henderson 165198cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 165298cd9ca7SRichard Henderson have already had nullification handled. */ 1653c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest, 165498cd9ca7SRichard Henderson unsigned link, bool is_n) 165598cd9ca7SRichard Henderson { 165698cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 165798cd9ca7SRichard Henderson if (link != 0) { 1658741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 165998cd9ca7SRichard Henderson } 166098cd9ca7SRichard Henderson ctx->iaoq_n = dest; 166198cd9ca7SRichard Henderson if (is_n) { 166298cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 166398cd9ca7SRichard Henderson } 166498cd9ca7SRichard Henderson } else { 166598cd9ca7SRichard Henderson nullify_over(ctx); 166698cd9ca7SRichard Henderson 166798cd9ca7SRichard Henderson if (link != 0) { 1668741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 166998cd9ca7SRichard Henderson } 167098cd9ca7SRichard Henderson 167198cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 167298cd9ca7SRichard Henderson nullify_set(ctx, 0); 167398cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 167498cd9ca7SRichard Henderson } else { 167598cd9ca7SRichard Henderson nullify_set(ctx, is_n); 167698cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 167798cd9ca7SRichard Henderson } 167898cd9ca7SRichard Henderson 167931234768SRichard Henderson nullify_end(ctx); 168098cd9ca7SRichard Henderson 168198cd9ca7SRichard Henderson nullify_set(ctx, 0); 168298cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 168331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 168498cd9ca7SRichard Henderson } 168501afb7beSRichard Henderson return true; 168698cd9ca7SRichard Henderson } 168798cd9ca7SRichard Henderson 168898cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 168998cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1690c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 169198cd9ca7SRichard Henderson DisasCond *cond) 169298cd9ca7SRichard Henderson { 1693c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, disp); 169498cd9ca7SRichard Henderson TCGLabel *taken = NULL; 169598cd9ca7SRichard Henderson TCGCond c = cond->c; 169698cd9ca7SRichard Henderson bool n; 169798cd9ca7SRichard Henderson 169898cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 169998cd9ca7SRichard Henderson 170098cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 170198cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 170201afb7beSRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 170398cd9ca7SRichard Henderson } 170498cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 170501afb7beSRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 170698cd9ca7SRichard Henderson } 170798cd9ca7SRichard Henderson 170898cd9ca7SRichard Henderson taken = gen_new_label(); 17096fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 171098cd9ca7SRichard Henderson cond_free(cond); 171198cd9ca7SRichard Henderson 171298cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 171398cd9ca7SRichard Henderson n = is_n && disp < 0; 171498cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 171598cd9ca7SRichard Henderson nullify_set(ctx, 0); 1716a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 171798cd9ca7SRichard Henderson } else { 171898cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 171998cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 172098cd9ca7SRichard Henderson ctx->null_lab = NULL; 172198cd9ca7SRichard Henderson } 172298cd9ca7SRichard Henderson nullify_set(ctx, n); 1723c301f34eSRichard Henderson if (ctx->iaoq_n == -1) { 1724c301f34eSRichard Henderson /* The temporary iaoq_n_var died at the branch above. 1725c301f34eSRichard Henderson Regenerate it here instead of saving it. */ 17266fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 1727c301f34eSRichard Henderson } 1728a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 172998cd9ca7SRichard Henderson } 173098cd9ca7SRichard Henderson 173198cd9ca7SRichard Henderson gen_set_label(taken); 173298cd9ca7SRichard Henderson 173398cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 173498cd9ca7SRichard Henderson n = is_n && disp >= 0; 173598cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 173698cd9ca7SRichard Henderson nullify_set(ctx, 0); 1737a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, dest, dest + 4); 173898cd9ca7SRichard Henderson } else { 173998cd9ca7SRichard Henderson nullify_set(ctx, n); 1740a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 174198cd9ca7SRichard Henderson } 174298cd9ca7SRichard Henderson 174398cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 174498cd9ca7SRichard Henderson if (ctx->null_lab) { 174598cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 174698cd9ca7SRichard Henderson ctx->null_lab = NULL; 174731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 174898cd9ca7SRichard Henderson } else { 174931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 175098cd9ca7SRichard Henderson } 175101afb7beSRichard Henderson return true; 175298cd9ca7SRichard Henderson } 175398cd9ca7SRichard Henderson 175498cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 175598cd9ca7SRichard Henderson nullification of the branch itself. */ 17566fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest, 175798cd9ca7SRichard Henderson unsigned link, bool is_n) 175898cd9ca7SRichard Henderson { 17596fd0c7bcSRichard Henderson TCGv_i64 a0, a1, next, tmp; 176098cd9ca7SRichard Henderson TCGCond c; 176198cd9ca7SRichard Henderson 176298cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 176398cd9ca7SRichard Henderson 176498cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 176598cd9ca7SRichard Henderson if (link != 0) { 1766741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 176798cd9ca7SRichard Henderson } 1768aac0f603SRichard Henderson next = tcg_temp_new_i64(); 17696fd0c7bcSRichard Henderson tcg_gen_mov_i64(next, dest); 177098cd9ca7SRichard Henderson if (is_n) { 1771c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1772a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next); 17736fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, next, 4); 1774a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 1775c301f34eSRichard Henderson nullify_set(ctx, 0); 177631234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 177701afb7beSRichard Henderson return true; 1778c301f34eSRichard Henderson } 177998cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 178098cd9ca7SRichard Henderson } 1781c301f34eSRichard Henderson ctx->iaoq_n = -1; 1782c301f34eSRichard Henderson ctx->iaoq_n_var = next; 178398cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 178498cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 178598cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 17864137cb83SRichard Henderson tracepoint in effect). Since the goto_ptr that we must use 178798cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 178898cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 178998cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 179098cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 179198cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 179298cd9ca7SRichard Henderson 179398cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 179498cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 179598cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 1796a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest); 1797aac0f603SRichard Henderson next = tcg_temp_new_i64(); 17986fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, dest, 4); 1799a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 180098cd9ca7SRichard Henderson 180198cd9ca7SRichard Henderson nullify_over(ctx); 180298cd9ca7SRichard Henderson if (link != 0) { 18039a91dd84SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 180498cd9ca7SRichard Henderson } 18057f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 180601afb7beSRichard Henderson return nullify_end(ctx); 180798cd9ca7SRichard Henderson } else { 180898cd9ca7SRichard Henderson c = ctx->null_cond.c; 180998cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 181098cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 181198cd9ca7SRichard Henderson 1812aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 1813aac0f603SRichard Henderson next = tcg_temp_new_i64(); 181498cd9ca7SRichard Henderson 1815741322f4SRichard Henderson copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var); 18166fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest); 181798cd9ca7SRichard Henderson ctx->iaoq_n = -1; 181898cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 181998cd9ca7SRichard Henderson 182098cd9ca7SRichard Henderson if (link != 0) { 18216fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 182298cd9ca7SRichard Henderson } 182398cd9ca7SRichard Henderson 182498cd9ca7SRichard Henderson if (is_n) { 182598cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 182698cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 182798cd9ca7SRichard Henderson to the branch. */ 18286fd0c7bcSRichard Henderson tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1); 182998cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 183098cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 183198cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 183298cd9ca7SRichard Henderson } else { 183398cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 183498cd9ca7SRichard Henderson } 183598cd9ca7SRichard Henderson } 183601afb7beSRichard Henderson return true; 183798cd9ca7SRichard Henderson } 183898cd9ca7SRichard Henderson 1839660eefe1SRichard Henderson /* Implement 1840660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1841660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1842660eefe1SRichard Henderson * else 1843660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1844660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1845660eefe1SRichard Henderson */ 18466fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1847660eefe1SRichard Henderson { 18486fd0c7bcSRichard Henderson TCGv_i64 dest; 1849660eefe1SRichard Henderson switch (ctx->privilege) { 1850660eefe1SRichard Henderson case 0: 1851660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 1852660eefe1SRichard Henderson return offset; 1853660eefe1SRichard Henderson case 3: 1854993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 1855aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18566fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1857660eefe1SRichard Henderson break; 1858660eefe1SRichard Henderson default: 1859aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18606fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 18616fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 18626fd0c7bcSRichard Henderson tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset); 1863660eefe1SRichard Henderson break; 1864660eefe1SRichard Henderson } 1865660eefe1SRichard Henderson return dest; 1866660eefe1SRichard Henderson } 1867660eefe1SRichard Henderson 1868ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 18697ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 18707ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 18717ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 18727ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 18737ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 18747ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 18757ad439dfSRichard Henderson aforementioned BE. */ 187631234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 18777ad439dfSRichard Henderson { 18786fd0c7bcSRichard Henderson TCGv_i64 tmp; 1879a0180973SRichard Henderson 18807ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 18817ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 18828b81968cSMichael Tokarev next insn within the privileged page. */ 18837ad439dfSRichard Henderson switch (ctx->null_cond.c) { 18847ad439dfSRichard Henderson case TCG_COND_NEVER: 18857ad439dfSRichard Henderson break; 18867ad439dfSRichard Henderson case TCG_COND_ALWAYS: 18876fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 18887ad439dfSRichard Henderson goto do_sigill; 18897ad439dfSRichard Henderson default: 18907ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 18917ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 18927ad439dfSRichard Henderson g_assert_not_reached(); 18937ad439dfSRichard Henderson } 18947ad439dfSRichard Henderson 18957ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 18967ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 18977ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 18987ad439dfSRichard Henderson under such conditions. */ 18997ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 19007ad439dfSRichard Henderson goto do_sigill; 19017ad439dfSRichard Henderson } 19027ad439dfSRichard Henderson 1903ebd0e151SRichard Henderson switch (ctx->iaoq_f & -4) { 19047ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 19052986721dSRichard Henderson gen_excp_1(EXCP_IMP); 190631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 190731234768SRichard Henderson break; 19087ad439dfSRichard Henderson 19097ad439dfSRichard Henderson case 0xb0: /* LWS */ 19107ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 191131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 191231234768SRichard Henderson break; 19137ad439dfSRichard Henderson 19147ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 19156fd0c7bcSRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27])); 1916aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 19176fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_gr[31], 3); 1918a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 19196fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 1920a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 192131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 192231234768SRichard Henderson break; 19237ad439dfSRichard Henderson 19247ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 19257ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 192631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 192731234768SRichard Henderson break; 19287ad439dfSRichard Henderson 19297ad439dfSRichard Henderson default: 19307ad439dfSRichard Henderson do_sigill: 19312986721dSRichard Henderson gen_excp_1(EXCP_ILL); 193231234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 193331234768SRichard Henderson break; 19347ad439dfSRichard Henderson } 19357ad439dfSRichard Henderson } 1936ba1d0b44SRichard Henderson #endif 19377ad439dfSRichard Henderson 1938deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 1939b2167459SRichard Henderson { 1940b2167459SRichard Henderson cond_free(&ctx->null_cond); 194131234768SRichard Henderson return true; 1942b2167459SRichard Henderson } 1943b2167459SRichard Henderson 194440f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 194598a9cb79SRichard Henderson { 194631234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 194798a9cb79SRichard Henderson } 194898a9cb79SRichard Henderson 1949e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 195098a9cb79SRichard Henderson { 195198a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 195298a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 195398a9cb79SRichard Henderson 195498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 195531234768SRichard Henderson return true; 195698a9cb79SRichard Henderson } 195798a9cb79SRichard Henderson 1958c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 195998a9cb79SRichard Henderson { 1960c603e14aSRichard Henderson unsigned rt = a->t; 19616fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, rt); 19626fd0c7bcSRichard Henderson tcg_gen_movi_i64(tmp, ctx->iaoq_f); 196398a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 196498a9cb79SRichard Henderson 196598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 196631234768SRichard Henderson return true; 196798a9cb79SRichard Henderson } 196898a9cb79SRichard Henderson 1969c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 197098a9cb79SRichard Henderson { 1971c603e14aSRichard Henderson unsigned rt = a->t; 1972c603e14aSRichard Henderson unsigned rs = a->sp; 197333423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 197498a9cb79SRichard Henderson 197533423472SRichard Henderson load_spr(ctx, t0, rs); 197633423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 197733423472SRichard Henderson 1978967662cdSRichard Henderson save_gpr(ctx, rt, t0); 197998a9cb79SRichard Henderson 198098a9cb79SRichard Henderson cond_free(&ctx->null_cond); 198131234768SRichard Henderson return true; 198298a9cb79SRichard Henderson } 198398a9cb79SRichard Henderson 1984c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 198598a9cb79SRichard Henderson { 1986c603e14aSRichard Henderson unsigned rt = a->t; 1987c603e14aSRichard Henderson unsigned ctl = a->r; 19886fd0c7bcSRichard Henderson TCGv_i64 tmp; 198998a9cb79SRichard Henderson 199098a9cb79SRichard Henderson switch (ctl) { 199135136a77SRichard Henderson case CR_SAR: 1992c603e14aSRichard Henderson if (a->e == 0) { 199398a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 199498a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 19956fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 199698a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 199735136a77SRichard Henderson goto done; 199898a9cb79SRichard Henderson } 199998a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 200035136a77SRichard Henderson goto done; 200135136a77SRichard Henderson case CR_IT: /* Interval Timer */ 200235136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 200335136a77SRichard Henderson nullify_over(ctx); 200498a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2005dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 200649c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 200731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 200849c29d6cSRichard Henderson } else { 200949c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 201049c29d6cSRichard Henderson } 201198a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 201231234768SRichard Henderson return nullify_end(ctx); 201398a9cb79SRichard Henderson case 26: 201498a9cb79SRichard Henderson case 27: 201598a9cb79SRichard Henderson break; 201698a9cb79SRichard Henderson default: 201798a9cb79SRichard Henderson /* All other control registers are privileged. */ 201835136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 201935136a77SRichard Henderson break; 202098a9cb79SRichard Henderson } 202198a9cb79SRichard Henderson 2022aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20236fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 202435136a77SRichard Henderson save_gpr(ctx, rt, tmp); 202535136a77SRichard Henderson 202635136a77SRichard Henderson done: 202798a9cb79SRichard Henderson cond_free(&ctx->null_cond); 202831234768SRichard Henderson return true; 202998a9cb79SRichard Henderson } 203098a9cb79SRichard Henderson 2031c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 203233423472SRichard Henderson { 2033c603e14aSRichard Henderson unsigned rr = a->r; 2034c603e14aSRichard Henderson unsigned rs = a->sp; 2035967662cdSRichard Henderson TCGv_i64 tmp; 203633423472SRichard Henderson 203733423472SRichard Henderson if (rs >= 5) { 203833423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 203933423472SRichard Henderson } 204033423472SRichard Henderson nullify_over(ctx); 204133423472SRichard Henderson 2042967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2043967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 204433423472SRichard Henderson 204533423472SRichard Henderson if (rs >= 4) { 2046967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2047494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 204833423472SRichard Henderson } else { 2049967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 205033423472SRichard Henderson } 205133423472SRichard Henderson 205231234768SRichard Henderson return nullify_end(ctx); 205333423472SRichard Henderson } 205433423472SRichard Henderson 2055c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 205698a9cb79SRichard Henderson { 2057c603e14aSRichard Henderson unsigned ctl = a->t; 20586fd0c7bcSRichard Henderson TCGv_i64 reg; 20596fd0c7bcSRichard Henderson TCGv_i64 tmp; 206098a9cb79SRichard Henderson 206135136a77SRichard Henderson if (ctl == CR_SAR) { 20624845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2063aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20646fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 206598a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 206698a9cb79SRichard Henderson 206798a9cb79SRichard Henderson cond_free(&ctx->null_cond); 206831234768SRichard Henderson return true; 206998a9cb79SRichard Henderson } 207098a9cb79SRichard Henderson 207135136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 207235136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 207335136a77SRichard Henderson 2074c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 207535136a77SRichard Henderson nullify_over(ctx); 20764c34bab0SHelge Deller 20774c34bab0SHelge Deller if (ctx->is_pa20) { 20784845f015SSven Schnelle reg = load_gpr(ctx, a->r); 20794c34bab0SHelge Deller } else { 20804c34bab0SHelge Deller reg = tcg_temp_new_i64(); 20814c34bab0SHelge Deller tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 20824c34bab0SHelge Deller } 20834845f015SSven Schnelle 208435136a77SRichard Henderson switch (ctl) { 208535136a77SRichard Henderson case CR_IT: 2086ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 208735136a77SRichard Henderson break; 20884f5f2548SRichard Henderson case CR_EIRR: 2089ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 20904f5f2548SRichard Henderson break; 20914f5f2548SRichard Henderson case CR_EIEM: 2092ad75a51eSRichard Henderson gen_helper_write_eiem(tcg_env, reg); 209331234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 20944f5f2548SRichard Henderson break; 20954f5f2548SRichard Henderson 209635136a77SRichard Henderson case CR_IIASQ: 209735136a77SRichard Henderson case CR_IIAOQ: 209835136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 209935136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2100aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21016fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 210235136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 21036fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 21046fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 210535136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 210635136a77SRichard Henderson break; 210735136a77SRichard Henderson 2108d5de20bdSSven Schnelle case CR_PID1: 2109d5de20bdSSven Schnelle case CR_PID2: 2110d5de20bdSSven Schnelle case CR_PID3: 2111d5de20bdSSven Schnelle case CR_PID4: 21126fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2113d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2114ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2115d5de20bdSSven Schnelle #endif 2116d5de20bdSSven Schnelle break; 2117d5de20bdSSven Schnelle 211835136a77SRichard Henderson default: 21196fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 212035136a77SRichard Henderson break; 212135136a77SRichard Henderson } 212231234768SRichard Henderson return nullify_end(ctx); 21234f5f2548SRichard Henderson #endif 212435136a77SRichard Henderson } 212535136a77SRichard Henderson 2126c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 212798a9cb79SRichard Henderson { 2128aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 212998a9cb79SRichard Henderson 21306fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 21316fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 213298a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 213398a9cb79SRichard Henderson 213498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 213531234768SRichard Henderson return true; 213698a9cb79SRichard Henderson } 213798a9cb79SRichard Henderson 2138e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 213998a9cb79SRichard Henderson { 21406fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 214198a9cb79SRichard Henderson 21422330504cSHelge Deller #ifdef CONFIG_USER_ONLY 21432330504cSHelge Deller /* We don't implement space registers in user mode. */ 21446fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 21452330504cSHelge Deller #else 2146967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2147967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 21482330504cSHelge Deller #endif 2149e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 215098a9cb79SRichard Henderson 215198a9cb79SRichard Henderson cond_free(&ctx->null_cond); 215231234768SRichard Henderson return true; 215398a9cb79SRichard Henderson } 215498a9cb79SRichard Henderson 2155e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2156e36f27efSRichard Henderson { 2157e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2158e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY 21596fd0c7bcSRichard Henderson TCGv_i64 tmp; 2160e1b5a5edSRichard Henderson 2161e1b5a5edSRichard Henderson nullify_over(ctx); 2162e1b5a5edSRichard Henderson 2163aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21646fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21656fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2166ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2167e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2168e1b5a5edSRichard Henderson 2169e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 217031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 217131234768SRichard Henderson return nullify_end(ctx); 2172e36f27efSRichard Henderson #endif 2173e1b5a5edSRichard Henderson } 2174e1b5a5edSRichard Henderson 2175e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2176e1b5a5edSRichard Henderson { 2177e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2178e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 21796fd0c7bcSRichard Henderson TCGv_i64 tmp; 2180e1b5a5edSRichard Henderson 2181e1b5a5edSRichard Henderson nullify_over(ctx); 2182e1b5a5edSRichard Henderson 2183aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21846fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21856fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2186ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2187e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2188e1b5a5edSRichard Henderson 2189e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 219031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 219131234768SRichard Henderson return nullify_end(ctx); 2192e36f27efSRichard Henderson #endif 2193e1b5a5edSRichard Henderson } 2194e1b5a5edSRichard Henderson 2195c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2196e1b5a5edSRichard Henderson { 2197e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2198c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 21996fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2200e1b5a5edSRichard Henderson nullify_over(ctx); 2201e1b5a5edSRichard Henderson 2202c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2203aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2204ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2205e1b5a5edSRichard Henderson 2206e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 220731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 220831234768SRichard Henderson return nullify_end(ctx); 2209c603e14aSRichard Henderson #endif 2210e1b5a5edSRichard Henderson } 2211f49b3537SRichard Henderson 2212e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2213f49b3537SRichard Henderson { 2214f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2215e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2216f49b3537SRichard Henderson nullify_over(ctx); 2217f49b3537SRichard Henderson 2218e36f27efSRichard Henderson if (rfi_r) { 2219ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2220f49b3537SRichard Henderson } else { 2221ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2222f49b3537SRichard Henderson } 222331234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 222407ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 222531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2226f49b3537SRichard Henderson 222731234768SRichard Henderson return nullify_end(ctx); 2228e36f27efSRichard Henderson #endif 2229f49b3537SRichard Henderson } 22306210db05SHelge Deller 2231e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2232e36f27efSRichard Henderson { 2233e36f27efSRichard Henderson return do_rfi(ctx, false); 2234e36f27efSRichard Henderson } 2235e36f27efSRichard Henderson 2236e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2237e36f27efSRichard Henderson { 2238e36f27efSRichard Henderson return do_rfi(ctx, true); 2239e36f27efSRichard Henderson } 2240e36f27efSRichard Henderson 224196927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 22426210db05SHelge Deller { 22436210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 224496927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 22456210db05SHelge Deller nullify_over(ctx); 2246ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 224731234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 224831234768SRichard Henderson return nullify_end(ctx); 224996927adbSRichard Henderson #endif 22506210db05SHelge Deller } 225196927adbSRichard Henderson 225296927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 225396927adbSRichard Henderson { 225496927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 225596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 225696927adbSRichard Henderson nullify_over(ctx); 2257ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 225896927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 225996927adbSRichard Henderson return nullify_end(ctx); 226096927adbSRichard Henderson #endif 226196927adbSRichard Henderson } 2262e1b5a5edSRichard Henderson 22634a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 22644a4554c6SHelge Deller { 22654a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22664a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY 22674a4554c6SHelge Deller nullify_over(ctx); 2268ad75a51eSRichard Henderson gen_helper_getshadowregs(tcg_env); 22694a4554c6SHelge Deller return nullify_end(ctx); 22704a4554c6SHelge Deller #endif 22714a4554c6SHelge Deller } 22724a4554c6SHelge Deller 2273deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 227498a9cb79SRichard Henderson { 2275deee69a1SRichard Henderson if (a->m) { 22766fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 22776fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 22786fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 227998a9cb79SRichard Henderson 228098a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 22816fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2282deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2283deee69a1SRichard Henderson } 228498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 228531234768SRichard Henderson return true; 228698a9cb79SRichard Henderson } 228798a9cb79SRichard Henderson 2288deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 228998a9cb79SRichard Henderson { 22906fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2291eed14219SRichard Henderson TCGv_i32 level, want; 22926fd0c7bcSRichard Henderson TCGv_i64 addr; 229398a9cb79SRichard Henderson 229498a9cb79SRichard Henderson nullify_over(ctx); 229598a9cb79SRichard Henderson 2296deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2297deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2298eed14219SRichard Henderson 2299deee69a1SRichard Henderson if (a->imm) { 2300*e5d487c9SRichard Henderson level = tcg_constant_i32(a->ri & 3); 230198a9cb79SRichard Henderson } else { 2302eed14219SRichard Henderson level = tcg_temp_new_i32(); 23036fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2304eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 230598a9cb79SRichard Henderson } 230629dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2307eed14219SRichard Henderson 2308ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2309eed14219SRichard Henderson 2310deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 231131234768SRichard Henderson return nullify_end(ctx); 231298a9cb79SRichard Henderson } 231398a9cb79SRichard Henderson 2314deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 23158d6ae7fbSRichard Henderson { 23168577f354SRichard Henderson if (ctx->is_pa20) { 23178577f354SRichard Henderson return false; 23188577f354SRichard Henderson } 2319deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2320deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23216fd0c7bcSRichard Henderson TCGv_i64 addr; 23226fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 23238d6ae7fbSRichard Henderson 23248d6ae7fbSRichard Henderson nullify_over(ctx); 23258d6ae7fbSRichard Henderson 2326deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2327deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2328deee69a1SRichard Henderson if (a->addr) { 23298577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 23308d6ae7fbSRichard Henderson } else { 23318577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 23328d6ae7fbSRichard Henderson } 23338d6ae7fbSRichard Henderson 233432dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 233532dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 233631234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 233731234768SRichard Henderson } 233831234768SRichard Henderson return nullify_end(ctx); 2339deee69a1SRichard Henderson #endif 23408d6ae7fbSRichard Henderson } 234163300a00SRichard Henderson 2342eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 234363300a00SRichard Henderson { 2344deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2345deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23466fd0c7bcSRichard Henderson TCGv_i64 addr; 23476fd0c7bcSRichard Henderson TCGv_i64 ofs; 234863300a00SRichard Henderson 234963300a00SRichard Henderson nullify_over(ctx); 235063300a00SRichard Henderson 2351deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2352eb25d10fSHelge Deller 2353eb25d10fSHelge Deller /* 2354eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2355eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2356eb25d10fSHelge Deller */ 2357eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2358eb25d10fSHelge Deller if (ctx->is_pa20) { 2359eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 236063300a00SRichard Henderson } 2361eb25d10fSHelge Deller 2362eb25d10fSHelge Deller if (local) { 2363eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 236463300a00SRichard Henderson } else { 2365ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 236663300a00SRichard Henderson } 236763300a00SRichard Henderson 2368eb25d10fSHelge Deller if (a->m) { 2369eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2370eb25d10fSHelge Deller } 2371eb25d10fSHelge Deller 2372eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2373eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2374eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2375eb25d10fSHelge Deller } 2376eb25d10fSHelge Deller return nullify_end(ctx); 2377eb25d10fSHelge Deller #endif 2378eb25d10fSHelge Deller } 2379eb25d10fSHelge Deller 2380eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2381eb25d10fSHelge Deller { 2382eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2383eb25d10fSHelge Deller } 2384eb25d10fSHelge Deller 2385eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2386eb25d10fSHelge Deller { 2387eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2388eb25d10fSHelge Deller } 2389eb25d10fSHelge Deller 2390eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2391eb25d10fSHelge Deller { 2392eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2393eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2394eb25d10fSHelge Deller nullify_over(ctx); 2395eb25d10fSHelge Deller 2396eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2397eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2398eb25d10fSHelge Deller 239963300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 240032dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 240131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 240231234768SRichard Henderson } 240331234768SRichard Henderson return nullify_end(ctx); 2404deee69a1SRichard Henderson #endif 240563300a00SRichard Henderson } 24062dfcca9fSRichard Henderson 24076797c315SNick Hudson /* 24086797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 24096797c315SNick Hudson * See 24106797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 24116797c315SNick Hudson * page 13-9 (195/206) 24126797c315SNick Hudson */ 24136797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 24146797c315SNick Hudson { 24158577f354SRichard Henderson if (ctx->is_pa20) { 24168577f354SRichard Henderson return false; 24178577f354SRichard Henderson } 24186797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24196797c315SNick Hudson #ifndef CONFIG_USER_ONLY 24206fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 24216fd0c7bcSRichard Henderson TCGv_i64 reg; 24226797c315SNick Hudson 24236797c315SNick Hudson nullify_over(ctx); 24246797c315SNick Hudson 24256797c315SNick Hudson /* 24266797c315SNick Hudson * FIXME: 24276797c315SNick Hudson * if (not (pcxl or pcxl2)) 24286797c315SNick Hudson * return gen_illegal(ctx); 24296797c315SNick Hudson */ 24306797c315SNick Hudson 24316fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 24326fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 24336fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 24346797c315SNick Hudson 2435ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 24366797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 24376797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2438ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 24396797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 24406797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 24416797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2442d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 24436797c315SNick Hudson 24446797c315SNick Hudson reg = load_gpr(ctx, a->r); 24456797c315SNick Hudson if (a->addr) { 24468577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 24476797c315SNick Hudson } else { 24488577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 24496797c315SNick Hudson } 24506797c315SNick Hudson 24516797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 24526797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 24536797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24546797c315SNick Hudson } 24556797c315SNick Hudson return nullify_end(ctx); 24566797c315SNick Hudson #endif 24576797c315SNick Hudson } 24586797c315SNick Hudson 24598577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 24608577f354SRichard Henderson { 24618577f354SRichard Henderson if (!ctx->is_pa20) { 24628577f354SRichard Henderson return false; 24638577f354SRichard Henderson } 24648577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24658577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 24668577f354SRichard Henderson nullify_over(ctx); 24678577f354SRichard Henderson { 24688577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 24698577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 24708577f354SRichard Henderson 24718577f354SRichard Henderson if (a->data) { 24728577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 24738577f354SRichard Henderson } else { 24748577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 24758577f354SRichard Henderson } 24768577f354SRichard Henderson } 24778577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 24788577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 24798577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24808577f354SRichard Henderson } 24818577f354SRichard Henderson return nullify_end(ctx); 24828577f354SRichard Henderson #endif 24838577f354SRichard Henderson } 24848577f354SRichard Henderson 2485deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 24862dfcca9fSRichard Henderson { 2487deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2488deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24896fd0c7bcSRichard Henderson TCGv_i64 vaddr; 24906fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 24912dfcca9fSRichard Henderson 24922dfcca9fSRichard Henderson nullify_over(ctx); 24932dfcca9fSRichard Henderson 2494deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 24952dfcca9fSRichard Henderson 2496aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2497ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 24982dfcca9fSRichard Henderson 24992dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2500deee69a1SRichard Henderson if (a->m) { 2501deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 25022dfcca9fSRichard Henderson } 2503deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 25042dfcca9fSRichard Henderson 250531234768SRichard Henderson return nullify_end(ctx); 2506deee69a1SRichard Henderson #endif 25072dfcca9fSRichard Henderson } 250843a97b81SRichard Henderson 2509deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 251043a97b81SRichard Henderson { 251143a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 251243a97b81SRichard Henderson 251343a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 251443a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 251543a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 251643a97b81SRichard Henderson since the entire address space is coherent. */ 2517a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 251843a97b81SRichard Henderson 251931234768SRichard Henderson cond_free(&ctx->null_cond); 252031234768SRichard Henderson return true; 252143a97b81SRichard Henderson } 252298a9cb79SRichard Henderson 2523faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2524b2167459SRichard Henderson { 25250c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2526b2167459SRichard Henderson } 2527b2167459SRichard Henderson 2528faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2529b2167459SRichard Henderson { 25300c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2531b2167459SRichard Henderson } 2532b2167459SRichard Henderson 2533faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2534b2167459SRichard Henderson { 25350c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2536b2167459SRichard Henderson } 2537b2167459SRichard Henderson 2538faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2539b2167459SRichard Henderson { 25400c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 25410c982a28SRichard Henderson } 2542b2167459SRichard Henderson 2543faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 25440c982a28SRichard Henderson { 25450c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 25460c982a28SRichard Henderson } 25470c982a28SRichard Henderson 254863c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 25490c982a28SRichard Henderson { 25500c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 25510c982a28SRichard Henderson } 25520c982a28SRichard Henderson 255363c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25540c982a28SRichard Henderson { 25550c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 25560c982a28SRichard Henderson } 25570c982a28SRichard Henderson 255863c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25590c982a28SRichard Henderson { 25600c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 25610c982a28SRichard Henderson } 25620c982a28SRichard Henderson 256363c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25640c982a28SRichard Henderson { 25650c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 25660c982a28SRichard Henderson } 25670c982a28SRichard Henderson 256863c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 25690c982a28SRichard Henderson { 25700c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 25710c982a28SRichard Henderson } 25720c982a28SRichard Henderson 257363c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25740c982a28SRichard Henderson { 25750c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 25760c982a28SRichard Henderson } 25770c982a28SRichard Henderson 2578fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 25790c982a28SRichard Henderson { 25806fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 25810c982a28SRichard Henderson } 25820c982a28SRichard Henderson 2583fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 25840c982a28SRichard Henderson { 25856fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 25860c982a28SRichard Henderson } 25870c982a28SRichard Henderson 2588fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 25890c982a28SRichard Henderson { 25900c982a28SRichard Henderson if (a->cf == 0) { 25910c982a28SRichard Henderson unsigned r2 = a->r2; 25920c982a28SRichard Henderson unsigned r1 = a->r1; 25930c982a28SRichard Henderson unsigned rt = a->t; 25940c982a28SRichard Henderson 25957aee8189SRichard Henderson if (rt == 0) { /* NOP */ 25967aee8189SRichard Henderson cond_free(&ctx->null_cond); 25977aee8189SRichard Henderson return true; 25987aee8189SRichard Henderson } 25997aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2600b2167459SRichard Henderson if (r1 == 0) { 26016fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 26026fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2603b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2604b2167459SRichard Henderson } else { 2605b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2606b2167459SRichard Henderson } 2607b2167459SRichard Henderson cond_free(&ctx->null_cond); 260831234768SRichard Henderson return true; 2609b2167459SRichard Henderson } 26107aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 26117aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 26127aee8189SRichard Henderson * 26137aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 26147aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 26157aee8189SRichard Henderson * currently implemented as idle. 26167aee8189SRichard Henderson */ 26177aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 26187aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 26197aee8189SRichard Henderson until the next timer interrupt. */ 26207aee8189SRichard Henderson nullify_over(ctx); 26217aee8189SRichard Henderson 26227aee8189SRichard Henderson /* Advance the instruction queue. */ 2623741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 2624741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 26257aee8189SRichard Henderson nullify_set(ctx, 0); 26267aee8189SRichard Henderson 26277aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2628ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 262929dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 26307aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 26317aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 26327aee8189SRichard Henderson 26337aee8189SRichard Henderson return nullify_end(ctx); 26347aee8189SRichard Henderson } 26357aee8189SRichard Henderson #endif 26367aee8189SRichard Henderson } 26376fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 26387aee8189SRichard Henderson } 2639b2167459SRichard Henderson 2640fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2641b2167459SRichard Henderson { 26426fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 26430c982a28SRichard Henderson } 26440c982a28SRichard Henderson 2645345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 26460c982a28SRichard Henderson { 26476fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2648b2167459SRichard Henderson 26490c982a28SRichard Henderson if (a->cf) { 2650b2167459SRichard Henderson nullify_over(ctx); 2651b2167459SRichard Henderson } 26520c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26530c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2654345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 265531234768SRichard Henderson return nullify_end(ctx); 2656b2167459SRichard Henderson } 2657b2167459SRichard Henderson 2658af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2659b2167459SRichard Henderson { 26606fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2661b2167459SRichard Henderson 26620c982a28SRichard Henderson if (a->cf) { 2663b2167459SRichard Henderson nullify_over(ctx); 2664b2167459SRichard Henderson } 26650c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26660c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 26676fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64); 266831234768SRichard Henderson return nullify_end(ctx); 2669b2167459SRichard Henderson } 2670b2167459SRichard Henderson 2671af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2672b2167459SRichard Henderson { 26736fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2674b2167459SRichard Henderson 26750c982a28SRichard Henderson if (a->cf) { 2676b2167459SRichard Henderson nullify_over(ctx); 2677b2167459SRichard Henderson } 26780c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26790c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2680aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 26816fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 26826fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64); 268331234768SRichard Henderson return nullify_end(ctx); 2684b2167459SRichard Henderson } 2685b2167459SRichard Henderson 2686af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2687b2167459SRichard Henderson { 26880c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 26890c982a28SRichard Henderson } 26900c982a28SRichard Henderson 2691af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 26920c982a28SRichard Henderson { 26930c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 26940c982a28SRichard Henderson } 26950c982a28SRichard Henderson 2696af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 26970c982a28SRichard Henderson { 26986fd0c7bcSRichard Henderson TCGv_i64 tmp; 2699b2167459SRichard Henderson 2700b2167459SRichard Henderson nullify_over(ctx); 2701b2167459SRichard Henderson 2702aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 27036fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, cpu_psw_cb, 3); 2704b2167459SRichard Henderson if (!is_i) { 27056fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2706b2167459SRichard Henderson } 27076fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 27086fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 2709af240753SRichard Henderson do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false, 27106fd0c7bcSRichard Henderson is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64); 271131234768SRichard Henderson return nullify_end(ctx); 2712b2167459SRichard Henderson } 2713b2167459SRichard Henderson 2714af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2715b2167459SRichard Henderson { 27160c982a28SRichard Henderson return do_dcor(ctx, a, false); 27170c982a28SRichard Henderson } 27180c982a28SRichard Henderson 2719af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 27200c982a28SRichard Henderson { 27210c982a28SRichard Henderson return do_dcor(ctx, a, true); 27220c982a28SRichard Henderson } 27230c982a28SRichard Henderson 27240c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 27250c982a28SRichard Henderson { 2726a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 27276fd0c7bcSRichard Henderson TCGv_i64 cout; 2728b2167459SRichard Henderson 2729b2167459SRichard Henderson nullify_over(ctx); 2730b2167459SRichard Henderson 27310c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 27320c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2733b2167459SRichard Henderson 2734aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2735aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2736aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2737aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2738b2167459SRichard Henderson 2739b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 27406fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 27416fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2742b2167459SRichard Henderson 274372ca8753SRichard Henderson /* 274472ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 274572ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 274672ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 274772ca8753SRichard Henderson * proper inputs to the addition without movcond. 274872ca8753SRichard Henderson */ 27496fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 27506fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 27516fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 275272ca8753SRichard Henderson 2753a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2754a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2755a4db4a78SRichard Henderson addc, ctx->zero); 2756b2167459SRichard Henderson 2757b2167459SRichard Henderson /* Write back the result register. */ 27580c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2759b2167459SRichard Henderson 2760b2167459SRichard Henderson /* Write back PSW[CB]. */ 27616fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 27626fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2763b2167459SRichard Henderson 2764b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 276572ca8753SRichard Henderson cout = get_psw_carry(ctx, false); 27666fd0c7bcSRichard Henderson tcg_gen_neg_i64(cpu_psw_v, cout); 27676fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2768b2167459SRichard Henderson 2769b2167459SRichard Henderson /* Install the new nullification. */ 27700c982a28SRichard Henderson if (a->cf) { 27716fd0c7bcSRichard Henderson TCGv_i64 sv = NULL; 2772b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2773b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 2774b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 2775b2167459SRichard Henderson } 2776a751eb31SRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv); 2777b2167459SRichard Henderson } 2778b2167459SRichard Henderson 277931234768SRichard Henderson return nullify_end(ctx); 2780b2167459SRichard Henderson } 2781b2167459SRichard Henderson 27820588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2783b2167459SRichard Henderson { 27840588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 27850588e061SRichard Henderson } 27860588e061SRichard Henderson 27870588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 27880588e061SRichard Henderson { 27890588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 27900588e061SRichard Henderson } 27910588e061SRichard Henderson 27920588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 27930588e061SRichard Henderson { 27940588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 27950588e061SRichard Henderson } 27960588e061SRichard Henderson 27970588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 27980588e061SRichard Henderson { 27990588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 28000588e061SRichard Henderson } 28010588e061SRichard Henderson 28020588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 28030588e061SRichard Henderson { 28040588e061SRichard Henderson return do_sub_imm(ctx, a, false); 28050588e061SRichard Henderson } 28060588e061SRichard Henderson 28070588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 28080588e061SRichard Henderson { 28090588e061SRichard Henderson return do_sub_imm(ctx, a, true); 28100588e061SRichard Henderson } 28110588e061SRichard Henderson 2812345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 28130588e061SRichard Henderson { 28146fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 2815b2167459SRichard Henderson 28160588e061SRichard Henderson if (a->cf) { 2817b2167459SRichard Henderson nullify_over(ctx); 2818b2167459SRichard Henderson } 2819b2167459SRichard Henderson 28206fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 28210588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 2822345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2823b2167459SRichard Henderson 282431234768SRichard Henderson return nullify_end(ctx); 2825b2167459SRichard Henderson } 2826b2167459SRichard Henderson 28270843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 28280843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 28290843563fSRichard Henderson { 28300843563fSRichard Henderson TCGv_i64 r1, r2, dest; 28310843563fSRichard Henderson 28320843563fSRichard Henderson if (!ctx->is_pa20) { 28330843563fSRichard Henderson return false; 28340843563fSRichard Henderson } 28350843563fSRichard Henderson 28360843563fSRichard Henderson nullify_over(ctx); 28370843563fSRichard Henderson 28380843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 28390843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 28400843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 28410843563fSRichard Henderson 28420843563fSRichard Henderson fn(dest, r1, r2); 28430843563fSRichard Henderson save_gpr(ctx, a->t, dest); 28440843563fSRichard Henderson 28450843563fSRichard Henderson return nullify_end(ctx); 28460843563fSRichard Henderson } 28470843563fSRichard Henderson 2848151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 2849151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 2850151f309bSRichard Henderson { 2851151f309bSRichard Henderson TCGv_i64 r, dest; 2852151f309bSRichard Henderson 2853151f309bSRichard Henderson if (!ctx->is_pa20) { 2854151f309bSRichard Henderson return false; 2855151f309bSRichard Henderson } 2856151f309bSRichard Henderson 2857151f309bSRichard Henderson nullify_over(ctx); 2858151f309bSRichard Henderson 2859151f309bSRichard Henderson r = load_gpr(ctx, a->r); 2860151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 2861151f309bSRichard Henderson 2862151f309bSRichard Henderson fn(dest, r, a->i); 2863151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 2864151f309bSRichard Henderson 2865151f309bSRichard Henderson return nullify_end(ctx); 2866151f309bSRichard Henderson } 2867151f309bSRichard Henderson 28683bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 28693bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 28703bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 28713bbb8e48SRichard Henderson { 28723bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 28733bbb8e48SRichard Henderson 28743bbb8e48SRichard Henderson if (!ctx->is_pa20) { 28753bbb8e48SRichard Henderson return false; 28763bbb8e48SRichard Henderson } 28773bbb8e48SRichard Henderson 28783bbb8e48SRichard Henderson nullify_over(ctx); 28793bbb8e48SRichard Henderson 28803bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 28813bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 28823bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 28833bbb8e48SRichard Henderson 28843bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 28853bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 28863bbb8e48SRichard Henderson 28873bbb8e48SRichard Henderson return nullify_end(ctx); 28883bbb8e48SRichard Henderson } 28893bbb8e48SRichard Henderson 28900843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 28910843563fSRichard Henderson { 28920843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 28930843563fSRichard Henderson } 28940843563fSRichard Henderson 28950843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 28960843563fSRichard Henderson { 28970843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 28980843563fSRichard Henderson } 28990843563fSRichard Henderson 29000843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 29010843563fSRichard Henderson { 29020843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 29030843563fSRichard Henderson } 29040843563fSRichard Henderson 29051b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 29061b3cb7c8SRichard Henderson { 29071b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 29081b3cb7c8SRichard Henderson } 29091b3cb7c8SRichard Henderson 2910151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 2911151f309bSRichard Henderson { 2912151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 2913151f309bSRichard Henderson } 2914151f309bSRichard Henderson 2915151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 2916151f309bSRichard Henderson { 2917151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 2918151f309bSRichard Henderson } 2919151f309bSRichard Henderson 2920151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 2921151f309bSRichard Henderson { 2922151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 2923151f309bSRichard Henderson } 2924151f309bSRichard Henderson 29253bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 29263bbb8e48SRichard Henderson { 29273bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 29283bbb8e48SRichard Henderson } 29293bbb8e48SRichard Henderson 29303bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 29313bbb8e48SRichard Henderson { 29323bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 29333bbb8e48SRichard Henderson } 29343bbb8e48SRichard Henderson 293510c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 293610c9e58dSRichard Henderson { 293710c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 293810c9e58dSRichard Henderson } 293910c9e58dSRichard Henderson 294010c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 294110c9e58dSRichard Henderson { 294210c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 294310c9e58dSRichard Henderson } 294410c9e58dSRichard Henderson 294510c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 294610c9e58dSRichard Henderson { 294710c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 294810c9e58dSRichard Henderson } 294910c9e58dSRichard Henderson 2950c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2951c2a7ee3fSRichard Henderson { 2952c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 2953c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2954c2a7ee3fSRichard Henderson 2955c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 2956c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 2957c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 2958c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2959c2a7ee3fSRichard Henderson } 2960c2a7ee3fSRichard Henderson 2961c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 2962c2a7ee3fSRichard Henderson { 2963c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 2964c2a7ee3fSRichard Henderson } 2965c2a7ee3fSRichard Henderson 2966c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2967c2a7ee3fSRichard Henderson { 2968c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 2969c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2970c2a7ee3fSRichard Henderson 2971c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 2972c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 2973c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 2974c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2975c2a7ee3fSRichard Henderson } 2976c2a7ee3fSRichard Henderson 2977c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 2978c2a7ee3fSRichard Henderson { 2979c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 2980c2a7ee3fSRichard Henderson } 2981c2a7ee3fSRichard Henderson 2982c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2983c2a7ee3fSRichard Henderson { 2984c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2985c2a7ee3fSRichard Henderson 2986c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 2987c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 2988c2a7ee3fSRichard Henderson } 2989c2a7ee3fSRichard Henderson 2990c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 2991c2a7ee3fSRichard Henderson { 2992c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 2993c2a7ee3fSRichard Henderson } 2994c2a7ee3fSRichard Henderson 2995c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2996c2a7ee3fSRichard Henderson { 2997c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 2998c2a7ee3fSRichard Henderson } 2999c2a7ee3fSRichard Henderson 3000c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 3001c2a7ee3fSRichard Henderson { 3002c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 3003c2a7ee3fSRichard Henderson } 3004c2a7ee3fSRichard Henderson 30054e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 30064e7abdb1SRichard Henderson { 30074e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 30084e7abdb1SRichard Henderson 30094e7abdb1SRichard Henderson if (!ctx->is_pa20) { 30104e7abdb1SRichard Henderson return false; 30114e7abdb1SRichard Henderson } 30124e7abdb1SRichard Henderson 30134e7abdb1SRichard Henderson nullify_over(ctx); 30144e7abdb1SRichard Henderson 30154e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 30164e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 30174e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 30184e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 30194e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 30204e7abdb1SRichard Henderson 30214e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 30224e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 30234e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 30244e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 30254e7abdb1SRichard Henderson 30264e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 30274e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 30284e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 30294e7abdb1SRichard Henderson 30304e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 30314e7abdb1SRichard Henderson return nullify_end(ctx); 30324e7abdb1SRichard Henderson } 30334e7abdb1SRichard Henderson 30341cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 303596d6407fSRichard Henderson { 3036b5caa17cSRichard Henderson if (ctx->is_pa20) { 3037b5caa17cSRichard Henderson /* 3038b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3039b5caa17cSRichard Henderson * Any base modification still occurs. 3040b5caa17cSRichard Henderson */ 3041b5caa17cSRichard Henderson if (a->t == 0) { 3042b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3043b5caa17cSRichard Henderson } 3044b5caa17cSRichard Henderson } else if (a->size > MO_32) { 30450786a3b6SHelge Deller return gen_illegal(ctx); 3046c53e401eSRichard Henderson } 30471cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 30481cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 304996d6407fSRichard Henderson } 305096d6407fSRichard Henderson 30511cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 305296d6407fSRichard Henderson { 30531cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3054c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 30550786a3b6SHelge Deller return gen_illegal(ctx); 305696d6407fSRichard Henderson } 3057c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 30580786a3b6SHelge Deller } 305996d6407fSRichard Henderson 30601cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 306196d6407fSRichard Henderson { 3062b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3063a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 30646fd0c7bcSRichard Henderson TCGv_i64 addr; 306596d6407fSRichard Henderson 3066c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 306751416c4eSRichard Henderson return gen_illegal(ctx); 306851416c4eSRichard Henderson } 306951416c4eSRichard Henderson 307096d6407fSRichard Henderson nullify_over(ctx); 307196d6407fSRichard Henderson 30721cd012a5SRichard Henderson if (a->m) { 307386f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 307486f8d05fSRichard Henderson we see the result of the load. */ 3075aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 307696d6407fSRichard Henderson } else { 30771cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 307896d6407fSRichard Henderson } 307996d6407fSRichard Henderson 30801cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0, 30811cd012a5SRichard Henderson a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX); 3082b1af755cSRichard Henderson 3083b1af755cSRichard Henderson /* 3084b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3085b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3086b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3087b1af755cSRichard Henderson * 3088b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3089b1af755cSRichard Henderson * with the ,co completer. 3090b1af755cSRichard Henderson */ 3091b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3092b1af755cSRichard Henderson 3093a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3094b1af755cSRichard Henderson 30951cd012a5SRichard Henderson if (a->m) { 30961cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 309796d6407fSRichard Henderson } 30981cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 309996d6407fSRichard Henderson 310031234768SRichard Henderson return nullify_end(ctx); 310196d6407fSRichard Henderson } 310296d6407fSRichard Henderson 31031cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 310496d6407fSRichard Henderson { 31056fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31066fd0c7bcSRichard Henderson TCGv_i64 addr; 310796d6407fSRichard Henderson 310896d6407fSRichard Henderson nullify_over(ctx); 310996d6407fSRichard Henderson 31101cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 311186f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 31121cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 31131cd012a5SRichard Henderson if (a->a) { 3114f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3115ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3116f9f46db4SEmilio G. Cota } else { 3117ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3118f9f46db4SEmilio G. Cota } 3119f9f46db4SEmilio G. Cota } else { 3120f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3121ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 312296d6407fSRichard Henderson } else { 3123ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 312496d6407fSRichard Henderson } 3125f9f46db4SEmilio G. Cota } 31261cd012a5SRichard Henderson if (a->m) { 31276fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 31281cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 312996d6407fSRichard Henderson } 313096d6407fSRichard Henderson 313131234768SRichard Henderson return nullify_end(ctx); 313296d6407fSRichard Henderson } 313396d6407fSRichard Henderson 313425460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 313525460fc5SRichard Henderson { 31366fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31376fd0c7bcSRichard Henderson TCGv_i64 addr; 313825460fc5SRichard Henderson 313925460fc5SRichard Henderson if (!ctx->is_pa20) { 314025460fc5SRichard Henderson return false; 314125460fc5SRichard Henderson } 314225460fc5SRichard Henderson nullify_over(ctx); 314325460fc5SRichard Henderson 314425460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 314525460fc5SRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 314625460fc5SRichard Henderson val = load_gpr(ctx, a->r); 314725460fc5SRichard Henderson if (a->a) { 314825460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 314925460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 315025460fc5SRichard Henderson } else { 315125460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 315225460fc5SRichard Henderson } 315325460fc5SRichard Henderson } else { 315425460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 315525460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 315625460fc5SRichard Henderson } else { 315725460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 315825460fc5SRichard Henderson } 315925460fc5SRichard Henderson } 316025460fc5SRichard Henderson if (a->m) { 31616fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 316225460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 316325460fc5SRichard Henderson } 316425460fc5SRichard Henderson 316525460fc5SRichard Henderson return nullify_end(ctx); 316625460fc5SRichard Henderson } 316725460fc5SRichard Henderson 31681cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3169d0a851ccSRichard Henderson { 3170d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3171d0a851ccSRichard Henderson 3172d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3173d0a851ccSRichard Henderson ctx->mmu_idx = MMU_PHYS_IDX; 31741cd012a5SRichard Henderson trans_ld(ctx, a); 3175d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 317631234768SRichard Henderson return true; 3177d0a851ccSRichard Henderson } 3178d0a851ccSRichard Henderson 31791cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3180d0a851ccSRichard Henderson { 3181d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3182d0a851ccSRichard Henderson 3183d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3184d0a851ccSRichard Henderson ctx->mmu_idx = MMU_PHYS_IDX; 31851cd012a5SRichard Henderson trans_st(ctx, a); 3186d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 318731234768SRichard Henderson return true; 3188d0a851ccSRichard Henderson } 318995412a61SRichard Henderson 31900588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3191b2167459SRichard Henderson { 31926fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3193b2167459SRichard Henderson 31946fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 31950588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3196b2167459SRichard Henderson cond_free(&ctx->null_cond); 319731234768SRichard Henderson return true; 3198b2167459SRichard Henderson } 3199b2167459SRichard Henderson 32000588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3201b2167459SRichard Henderson { 32026fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 32036fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3204b2167459SRichard Henderson 32056fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3206b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3207b2167459SRichard Henderson cond_free(&ctx->null_cond); 320831234768SRichard Henderson return true; 3209b2167459SRichard Henderson } 3210b2167459SRichard Henderson 32110588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3212b2167459SRichard Henderson { 32136fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3214b2167459SRichard Henderson 3215b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3216d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 32170588e061SRichard Henderson if (a->b == 0) { 32186fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3219b2167459SRichard Henderson } else { 32206fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3221b2167459SRichard Henderson } 32220588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3223b2167459SRichard Henderson cond_free(&ctx->null_cond); 322431234768SRichard Henderson return true; 3225b2167459SRichard Henderson } 3226b2167459SRichard Henderson 32276fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3228e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 322998cd9ca7SRichard Henderson { 32306fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 323198cd9ca7SRichard Henderson DisasCond cond; 323298cd9ca7SRichard Henderson 323398cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3234aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 323598cd9ca7SRichard Henderson 32366fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 323798cd9ca7SRichard Henderson 3238f764718dSRichard Henderson sv = NULL; 3239b47a4a02SSven Schnelle if (cond_need_sv(c)) { 324098cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 324198cd9ca7SRichard Henderson } 324298cd9ca7SRichard Henderson 32434fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 324401afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 324598cd9ca7SRichard Henderson } 324698cd9ca7SRichard Henderson 324701afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 324898cd9ca7SRichard Henderson { 3249e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3250e9efd4bcSRichard Henderson return false; 3251e9efd4bcSRichard Henderson } 325201afb7beSRichard Henderson nullify_over(ctx); 3253e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3254e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 325501afb7beSRichard Henderson } 325601afb7beSRichard Henderson 325701afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 325801afb7beSRichard Henderson { 3259c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3260c65c3ee1SRichard Henderson return false; 3261c65c3ee1SRichard Henderson } 326201afb7beSRichard Henderson nullify_over(ctx); 32636fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3264c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 326501afb7beSRichard Henderson } 326601afb7beSRichard Henderson 32676fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 326801afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 326901afb7beSRichard Henderson { 32706fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 327198cd9ca7SRichard Henderson DisasCond cond; 3272bdcccc17SRichard Henderson bool d = false; 327398cd9ca7SRichard Henderson 3274f25d3160SRichard Henderson /* 3275f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3276f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3277f25d3160SRichard Henderson */ 3278f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3279f25d3160SRichard Henderson d = c >= 5; 3280f25d3160SRichard Henderson if (d) { 3281f25d3160SRichard Henderson c &= 3; 3282f25d3160SRichard Henderson } 3283f25d3160SRichard Henderson } 3284f25d3160SRichard Henderson 328598cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3286aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3287f764718dSRichard Henderson sv = NULL; 3288bdcccc17SRichard Henderson cb_cond = NULL; 328998cd9ca7SRichard Henderson 3290b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3291aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3292aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3293bdcccc17SRichard Henderson 32946fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 32956fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 32966fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 32976fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3298bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3299b47a4a02SSven Schnelle } else { 33006fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3301b47a4a02SSven Schnelle } 3302b47a4a02SSven Schnelle if (cond_need_sv(c)) { 330398cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 330498cd9ca7SRichard Henderson } 330598cd9ca7SRichard Henderson 3306a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 330743675d20SSven Schnelle save_gpr(ctx, r, dest); 330801afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 330998cd9ca7SRichard Henderson } 331098cd9ca7SRichard Henderson 331101afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 331298cd9ca7SRichard Henderson { 331301afb7beSRichard Henderson nullify_over(ctx); 331401afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 331501afb7beSRichard Henderson } 331601afb7beSRichard Henderson 331701afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 331801afb7beSRichard Henderson { 331901afb7beSRichard Henderson nullify_over(ctx); 33206fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 332101afb7beSRichard Henderson } 332201afb7beSRichard Henderson 332301afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 332401afb7beSRichard Henderson { 33256fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 332698cd9ca7SRichard Henderson DisasCond cond; 332798cd9ca7SRichard Henderson 332898cd9ca7SRichard Henderson nullify_over(ctx); 332998cd9ca7SRichard Henderson 3330aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 333101afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 333284e224d4SRichard Henderson if (cond_need_ext(ctx, a->d)) { 33331e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 33346fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 33356fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 33361e9ab9fbSRichard Henderson } else { 33376fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 33381e9ab9fbSRichard Henderson } 333998cd9ca7SRichard Henderson 33401e9ab9fbSRichard Henderson cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 334101afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 334298cd9ca7SRichard Henderson } 334398cd9ca7SRichard Henderson 334401afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 334598cd9ca7SRichard Henderson { 33466fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 334701afb7beSRichard Henderson DisasCond cond; 33481e9ab9fbSRichard Henderson int p; 334901afb7beSRichard Henderson 335001afb7beSRichard Henderson nullify_over(ctx); 335101afb7beSRichard Henderson 3352aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 335301afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 335484e224d4SRichard Henderson p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0); 33556fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, tcg_r, p); 335601afb7beSRichard Henderson 335701afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 335801afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 335901afb7beSRichard Henderson } 336001afb7beSRichard Henderson 336101afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 336201afb7beSRichard Henderson { 33636fd0c7bcSRichard Henderson TCGv_i64 dest; 336498cd9ca7SRichard Henderson DisasCond cond; 336598cd9ca7SRichard Henderson 336698cd9ca7SRichard Henderson nullify_over(ctx); 336798cd9ca7SRichard Henderson 336801afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 336901afb7beSRichard Henderson if (a->r1 == 0) { 33706fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 337198cd9ca7SRichard Henderson } else { 33726fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 337398cd9ca7SRichard Henderson } 337498cd9ca7SRichard Henderson 33754fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 33764fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 337701afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 337801afb7beSRichard Henderson } 337901afb7beSRichard Henderson 338001afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 338101afb7beSRichard Henderson { 33826fd0c7bcSRichard Henderson TCGv_i64 dest; 338301afb7beSRichard Henderson DisasCond cond; 338401afb7beSRichard Henderson 338501afb7beSRichard Henderson nullify_over(ctx); 338601afb7beSRichard Henderson 338701afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 33886fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 338901afb7beSRichard Henderson 33904fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 33914fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 339201afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 339398cd9ca7SRichard Henderson } 339498cd9ca7SRichard Henderson 3395f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 33960b1347d2SRichard Henderson { 33976fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 33980b1347d2SRichard Henderson 3399f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3400f7b775a9SRichard Henderson return false; 3401f7b775a9SRichard Henderson } 340230878590SRichard Henderson if (a->c) { 34030b1347d2SRichard Henderson nullify_over(ctx); 34040b1347d2SRichard Henderson } 34050b1347d2SRichard Henderson 340630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3407f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 340830878590SRichard Henderson if (a->r1 == 0) { 3409f7b775a9SRichard Henderson if (a->d) { 34106fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3411f7b775a9SRichard Henderson } else { 3412aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3413f7b775a9SRichard Henderson 34146fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 34156fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 34166fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3417f7b775a9SRichard Henderson } 341830878590SRichard Henderson } else if (a->r1 == a->r2) { 3419f7b775a9SRichard Henderson if (a->d) { 34206fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3421f7b775a9SRichard Henderson } else { 34220b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3423e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3424e1d635e8SRichard Henderson 34256fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 34266fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3427f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3428e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 34296fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3430f7b775a9SRichard Henderson } 3431f7b775a9SRichard Henderson } else { 34326fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3433f7b775a9SRichard Henderson 3434f7b775a9SRichard Henderson if (a->d) { 3435aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3436aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3437f7b775a9SRichard Henderson 34386fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 34396fd0c7bcSRichard Henderson tcg_gen_shl_i64(t, src2, n); 34406fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 34416fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src1, cpu_sar); 34426fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 34430b1347d2SRichard Henderson } else { 34440b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 34450b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 34460b1347d2SRichard Henderson 34476fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3448967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3449967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 34500b1347d2SRichard Henderson } 3451f7b775a9SRichard Henderson } 345230878590SRichard Henderson save_gpr(ctx, a->t, dest); 34530b1347d2SRichard Henderson 34540b1347d2SRichard Henderson /* Install the new nullification. */ 34550b1347d2SRichard Henderson cond_free(&ctx->null_cond); 345630878590SRichard Henderson if (a->c) { 34574fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 34580b1347d2SRichard Henderson } 345931234768SRichard Henderson return nullify_end(ctx); 34600b1347d2SRichard Henderson } 34610b1347d2SRichard Henderson 3462f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 34630b1347d2SRichard Henderson { 3464f7b775a9SRichard Henderson unsigned width, sa; 34656fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 34660b1347d2SRichard Henderson 3467f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3468f7b775a9SRichard Henderson return false; 3469f7b775a9SRichard Henderson } 347030878590SRichard Henderson if (a->c) { 34710b1347d2SRichard Henderson nullify_over(ctx); 34720b1347d2SRichard Henderson } 34730b1347d2SRichard Henderson 3474f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3475f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3476f7b775a9SRichard Henderson 347730878590SRichard Henderson dest = dest_gpr(ctx, a->t); 347830878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 347905bfd4dbSRichard Henderson if (a->r1 == 0) { 34806fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3481c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 34826fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3483f7b775a9SRichard Henderson } else { 3484f7b775a9SRichard Henderson assert(!a->d); 3485f7b775a9SRichard Henderson if (a->r1 == a->r2) { 34860b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 34876fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 34880b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 34896fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 34900b1347d2SRichard Henderson } else { 3491967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3492967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 34930b1347d2SRichard Henderson } 3494f7b775a9SRichard Henderson } 349530878590SRichard Henderson save_gpr(ctx, a->t, dest); 34960b1347d2SRichard Henderson 34970b1347d2SRichard Henderson /* Install the new nullification. */ 34980b1347d2SRichard Henderson cond_free(&ctx->null_cond); 349930878590SRichard Henderson if (a->c) { 35004fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 35010b1347d2SRichard Henderson } 350231234768SRichard Henderson return nullify_end(ctx); 35030b1347d2SRichard Henderson } 35040b1347d2SRichard Henderson 3505bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 35060b1347d2SRichard Henderson { 3507bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 35086fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 35090b1347d2SRichard Henderson 3510bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3511bd792da3SRichard Henderson return false; 3512bd792da3SRichard Henderson } 351330878590SRichard Henderson if (a->c) { 35140b1347d2SRichard Henderson nullify_over(ctx); 35150b1347d2SRichard Henderson } 35160b1347d2SRichard Henderson 351730878590SRichard Henderson dest = dest_gpr(ctx, a->t); 351830878590SRichard Henderson src = load_gpr(ctx, a->r); 3519aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 35200b1347d2SRichard Henderson 35210b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 35226fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 35236fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3524d781cb77SRichard Henderson 352530878590SRichard Henderson if (a->se) { 3526bd792da3SRichard Henderson if (!a->d) { 35276fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3528bd792da3SRichard Henderson src = dest; 3529bd792da3SRichard Henderson } 35306fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 35316fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 35320b1347d2SRichard Henderson } else { 3533bd792da3SRichard Henderson if (!a->d) { 35346fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3535bd792da3SRichard Henderson src = dest; 3536bd792da3SRichard Henderson } 35376fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 35386fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 35390b1347d2SRichard Henderson } 354030878590SRichard Henderson save_gpr(ctx, a->t, dest); 35410b1347d2SRichard Henderson 35420b1347d2SRichard Henderson /* Install the new nullification. */ 35430b1347d2SRichard Henderson cond_free(&ctx->null_cond); 354430878590SRichard Henderson if (a->c) { 3545bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35460b1347d2SRichard Henderson } 354731234768SRichard Henderson return nullify_end(ctx); 35480b1347d2SRichard Henderson } 35490b1347d2SRichard Henderson 3550bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 35510b1347d2SRichard Henderson { 3552bd792da3SRichard Henderson unsigned len, cpos, width; 35536fd0c7bcSRichard Henderson TCGv_i64 dest, src; 35540b1347d2SRichard Henderson 3555bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3556bd792da3SRichard Henderson return false; 3557bd792da3SRichard Henderson } 355830878590SRichard Henderson if (a->c) { 35590b1347d2SRichard Henderson nullify_over(ctx); 35600b1347d2SRichard Henderson } 35610b1347d2SRichard Henderson 3562bd792da3SRichard Henderson len = a->len; 3563bd792da3SRichard Henderson width = a->d ? 64 : 32; 3564bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3565bd792da3SRichard Henderson if (cpos + len > width) { 3566bd792da3SRichard Henderson len = width - cpos; 3567bd792da3SRichard Henderson } 3568bd792da3SRichard Henderson 356930878590SRichard Henderson dest = dest_gpr(ctx, a->t); 357030878590SRichard Henderson src = load_gpr(ctx, a->r); 357130878590SRichard Henderson if (a->se) { 35726fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 35730b1347d2SRichard Henderson } else { 35746fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 35750b1347d2SRichard Henderson } 357630878590SRichard Henderson save_gpr(ctx, a->t, dest); 35770b1347d2SRichard Henderson 35780b1347d2SRichard Henderson /* Install the new nullification. */ 35790b1347d2SRichard Henderson cond_free(&ctx->null_cond); 358030878590SRichard Henderson if (a->c) { 3581bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35820b1347d2SRichard Henderson } 358331234768SRichard Henderson return nullify_end(ctx); 35840b1347d2SRichard Henderson } 35850b1347d2SRichard Henderson 358672ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 35870b1347d2SRichard Henderson { 358872ae4f2bSRichard Henderson unsigned len, width; 3589c53e401eSRichard Henderson uint64_t mask0, mask1; 35906fd0c7bcSRichard Henderson TCGv_i64 dest; 35910b1347d2SRichard Henderson 359272ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 359372ae4f2bSRichard Henderson return false; 359472ae4f2bSRichard Henderson } 359530878590SRichard Henderson if (a->c) { 35960b1347d2SRichard Henderson nullify_over(ctx); 35970b1347d2SRichard Henderson } 359872ae4f2bSRichard Henderson 359972ae4f2bSRichard Henderson len = a->len; 360072ae4f2bSRichard Henderson width = a->d ? 64 : 32; 360172ae4f2bSRichard Henderson if (a->cpos + len > width) { 360272ae4f2bSRichard Henderson len = width - a->cpos; 36030b1347d2SRichard Henderson } 36040b1347d2SRichard Henderson 360530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 360630878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 360730878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 36080b1347d2SRichard Henderson 360930878590SRichard Henderson if (a->nz) { 36106fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 36116fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 36126fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 36130b1347d2SRichard Henderson } else { 36146fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 36150b1347d2SRichard Henderson } 361630878590SRichard Henderson save_gpr(ctx, a->t, dest); 36170b1347d2SRichard Henderson 36180b1347d2SRichard Henderson /* Install the new nullification. */ 36190b1347d2SRichard Henderson cond_free(&ctx->null_cond); 362030878590SRichard Henderson if (a->c) { 362172ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36220b1347d2SRichard Henderson } 362331234768SRichard Henderson return nullify_end(ctx); 36240b1347d2SRichard Henderson } 36250b1347d2SRichard Henderson 362672ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 36270b1347d2SRichard Henderson { 362830878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 362972ae4f2bSRichard Henderson unsigned len, width; 36306fd0c7bcSRichard Henderson TCGv_i64 dest, val; 36310b1347d2SRichard Henderson 363272ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 363372ae4f2bSRichard Henderson return false; 363472ae4f2bSRichard Henderson } 363530878590SRichard Henderson if (a->c) { 36360b1347d2SRichard Henderson nullify_over(ctx); 36370b1347d2SRichard Henderson } 363872ae4f2bSRichard Henderson 363972ae4f2bSRichard Henderson len = a->len; 364072ae4f2bSRichard Henderson width = a->d ? 64 : 32; 364172ae4f2bSRichard Henderson if (a->cpos + len > width) { 364272ae4f2bSRichard Henderson len = width - a->cpos; 36430b1347d2SRichard Henderson } 36440b1347d2SRichard Henderson 364530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 364630878590SRichard Henderson val = load_gpr(ctx, a->r); 36470b1347d2SRichard Henderson if (rs == 0) { 36486fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 36490b1347d2SRichard Henderson } else { 36506fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 36510b1347d2SRichard Henderson } 365230878590SRichard Henderson save_gpr(ctx, a->t, dest); 36530b1347d2SRichard Henderson 36540b1347d2SRichard Henderson /* Install the new nullification. */ 36550b1347d2SRichard Henderson cond_free(&ctx->null_cond); 365630878590SRichard Henderson if (a->c) { 365772ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36580b1347d2SRichard Henderson } 365931234768SRichard Henderson return nullify_end(ctx); 36600b1347d2SRichard Henderson } 36610b1347d2SRichard Henderson 366272ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 36636fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 36640b1347d2SRichard Henderson { 36650b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 366672ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 36676fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3668c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 36690b1347d2SRichard Henderson 36700b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3671aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3672aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 36730b1347d2SRichard Henderson 36740b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 36756fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 36766fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 36770b1347d2SRichard Henderson 3678aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 36796fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 36806fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 36810b1347d2SRichard Henderson if (rs) { 36826fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 36836fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 36846fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 36856fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 36860b1347d2SRichard Henderson } else { 36876fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 36880b1347d2SRichard Henderson } 36890b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 36900b1347d2SRichard Henderson 36910b1347d2SRichard Henderson /* Install the new nullification. */ 36920b1347d2SRichard Henderson cond_free(&ctx->null_cond); 36930b1347d2SRichard Henderson if (c) { 369472ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 36950b1347d2SRichard Henderson } 369631234768SRichard Henderson return nullify_end(ctx); 36970b1347d2SRichard Henderson } 36980b1347d2SRichard Henderson 369972ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 370030878590SRichard Henderson { 370172ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 370272ae4f2bSRichard Henderson return false; 370372ae4f2bSRichard Henderson } 3704a6deecceSSven Schnelle if (a->c) { 3705a6deecceSSven Schnelle nullify_over(ctx); 3706a6deecceSSven Schnelle } 370772ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 370872ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 370930878590SRichard Henderson } 371030878590SRichard Henderson 371172ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 371230878590SRichard Henderson { 371372ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 371472ae4f2bSRichard Henderson return false; 371572ae4f2bSRichard Henderson } 3716a6deecceSSven Schnelle if (a->c) { 3717a6deecceSSven Schnelle nullify_over(ctx); 3718a6deecceSSven Schnelle } 371972ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 37206fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 372130878590SRichard Henderson } 37220b1347d2SRichard Henderson 37238340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 372498cd9ca7SRichard Henderson { 37256fd0c7bcSRichard Henderson TCGv_i64 tmp; 372698cd9ca7SRichard Henderson 3727c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 372898cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 372998cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 373098cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 373198cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 373298cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 373398cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 373498cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 373598cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 37368340f534SRichard Henderson if (a->b == 0) { 37378340f534SRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 373898cd9ca7SRichard Henderson } 3739c301f34eSRichard Henderson #else 3740c301f34eSRichard Henderson nullify_over(ctx); 3741660eefe1SRichard Henderson #endif 3742660eefe1SRichard Henderson 3743aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37446fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp); 3745660eefe1SRichard Henderson tmp = do_ibranch_priv(ctx, tmp); 3746c301f34eSRichard Henderson 3747c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 37488340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3749c301f34eSRichard Henderson #else 3750c301f34eSRichard Henderson TCGv_i64 new_spc = tcg_temp_new_i64(); 3751c301f34eSRichard Henderson 37528340f534SRichard Henderson load_spr(ctx, new_spc, a->sp); 37538340f534SRichard Henderson if (a->l) { 3754741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); 3755c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); 3756c301f34eSRichard Henderson } 37578340f534SRichard Henderson if (a->n && use_nullify_skip(ctx)) { 3758a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 37596fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 3760a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3761c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, new_spc); 3762c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); 3763c301f34eSRichard Henderson } else { 3764741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3765c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3766c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3767c301f34eSRichard Henderson } 3768a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3769c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, new_spc); 37708340f534SRichard Henderson nullify_set(ctx, a->n); 3771c301f34eSRichard Henderson } 3772c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 377331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 377431234768SRichard Henderson return nullify_end(ctx); 3775c301f34eSRichard Henderson #endif 377698cd9ca7SRichard Henderson } 377798cd9ca7SRichard Henderson 37788340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 377998cd9ca7SRichard Henderson { 37808340f534SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n); 378198cd9ca7SRichard Henderson } 378298cd9ca7SRichard Henderson 37838340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 378443e05652SRichard Henderson { 3785c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, a->disp); 378643e05652SRichard Henderson 37876e5f5300SSven Schnelle nullify_over(ctx); 37886e5f5300SSven Schnelle 378943e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 379043e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 379143e05652SRichard Henderson * expensive to track. Real hardware will trap for 379243e05652SRichard Henderson * b gateway 379343e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 379443e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 379543e05652SRichard Henderson * diagnose the security hole 379643e05652SRichard Henderson * b gateway 379743e05652SRichard Henderson * b evil 379843e05652SRichard Henderson * in which instructions at evil would run with increased privs. 379943e05652SRichard Henderson */ 380043e05652SRichard Henderson if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) { 380143e05652SRichard Henderson return gen_illegal(ctx); 380243e05652SRichard Henderson } 380343e05652SRichard Henderson 380443e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 380543e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 3806b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(ctx->cs); 380743e05652SRichard Henderson int type = hppa_artype_for_page(env, ctx->base.pc_next); 380843e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 380943e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 381043e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 381143e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 381243e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 381343e05652SRichard Henderson if (type < 0) { 381431234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 381531234768SRichard Henderson return true; 381643e05652SRichard Henderson } 381743e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 381843e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 381943e05652SRichard Henderson dest = deposit32(dest, 0, 2, type - 4); 382043e05652SRichard Henderson } 382143e05652SRichard Henderson } else { 382243e05652SRichard Henderson dest &= -4; /* priv = 0 */ 382343e05652SRichard Henderson } 382443e05652SRichard Henderson #endif 382543e05652SRichard Henderson 38266e5f5300SSven Schnelle if (a->l) { 38276fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 38286e5f5300SSven Schnelle if (ctx->privilege < 3) { 38296fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 38306e5f5300SSven Schnelle } 38316fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 38326e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 38336e5f5300SSven Schnelle } 38346e5f5300SSven Schnelle 38356e5f5300SSven Schnelle return do_dbranch(ctx, dest, 0, a->n); 383643e05652SRichard Henderson } 383743e05652SRichard Henderson 38388340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 383998cd9ca7SRichard Henderson { 3840b35aec85SRichard Henderson if (a->x) { 3841aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 38426fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3); 38436fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8); 3844660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 38458340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3846b35aec85SRichard Henderson } else { 3847b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 3848b35aec85SRichard Henderson return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n); 3849b35aec85SRichard Henderson } 385098cd9ca7SRichard Henderson } 385198cd9ca7SRichard Henderson 38528340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 385398cd9ca7SRichard Henderson { 38546fd0c7bcSRichard Henderson TCGv_i64 dest; 385598cd9ca7SRichard Henderson 38568340f534SRichard Henderson if (a->x == 0) { 38578340f534SRichard Henderson dest = load_gpr(ctx, a->b); 385898cd9ca7SRichard Henderson } else { 3859aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 38606fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 38616fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 386298cd9ca7SRichard Henderson } 3863660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 38648340f534SRichard Henderson return do_ibranch(ctx, dest, 0, a->n); 386598cd9ca7SRichard Henderson } 386698cd9ca7SRichard Henderson 38678340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 386898cd9ca7SRichard Henderson { 38696fd0c7bcSRichard Henderson TCGv_i64 dest; 387098cd9ca7SRichard Henderson 3871c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 38728340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 38738340f534SRichard Henderson return do_ibranch(ctx, dest, a->l, a->n); 3874c301f34eSRichard Henderson #else 3875c301f34eSRichard Henderson nullify_over(ctx); 38768340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3877c301f34eSRichard Henderson 3878741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3879c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3880c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3881c301f34eSRichard Henderson } 3882741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest); 3883c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); 38848340f534SRichard Henderson if (a->l) { 3885741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var); 3886c301f34eSRichard Henderson } 38878340f534SRichard Henderson nullify_set(ctx, a->n); 3888c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 388931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 389031234768SRichard Henderson return nullify_end(ctx); 3891c301f34eSRichard Henderson #endif 389298cd9ca7SRichard Henderson } 389398cd9ca7SRichard Henderson 3894a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 3895a8966ba7SRichard Henderson { 3896a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 3897a8966ba7SRichard Henderson return ctx->is_pa20; 3898a8966ba7SRichard Henderson } 3899a8966ba7SRichard Henderson 39001ca74648SRichard Henderson /* 39011ca74648SRichard Henderson * Float class 0 39021ca74648SRichard Henderson */ 3903ebe9383cSRichard Henderson 39041ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3905ebe9383cSRichard Henderson { 3906ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3907ebe9383cSRichard Henderson } 3908ebe9383cSRichard Henderson 390959f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 391059f8c04bSHelge Deller { 3911a300dad3SRichard Henderson uint64_t ret; 3912a300dad3SRichard Henderson 3913c53e401eSRichard Henderson if (ctx->is_pa20) { 3914a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 3915a300dad3SRichard Henderson } else { 3916a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 3917a300dad3SRichard Henderson } 3918a300dad3SRichard Henderson 391959f8c04bSHelge Deller nullify_over(ctx); 3920a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 392159f8c04bSHelge Deller return nullify_end(ctx); 392259f8c04bSHelge Deller } 392359f8c04bSHelge Deller 39241ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 39251ca74648SRichard Henderson { 39261ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 39271ca74648SRichard Henderson } 39281ca74648SRichard Henderson 3929ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3930ebe9383cSRichard Henderson { 3931ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 3932ebe9383cSRichard Henderson } 3933ebe9383cSRichard Henderson 39341ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 39351ca74648SRichard Henderson { 39361ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 39371ca74648SRichard Henderson } 39381ca74648SRichard Henderson 39391ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3940ebe9383cSRichard Henderson { 3941ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 3942ebe9383cSRichard Henderson } 3943ebe9383cSRichard Henderson 39441ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 39451ca74648SRichard Henderson { 39461ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 39471ca74648SRichard Henderson } 39481ca74648SRichard Henderson 3949ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3950ebe9383cSRichard Henderson { 3951ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 3952ebe9383cSRichard Henderson } 3953ebe9383cSRichard Henderson 39541ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 39551ca74648SRichard Henderson { 39561ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 39571ca74648SRichard Henderson } 39581ca74648SRichard Henderson 39591ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 39601ca74648SRichard Henderson { 39611ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 39621ca74648SRichard Henderson } 39631ca74648SRichard Henderson 39641ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 39651ca74648SRichard Henderson { 39661ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 39671ca74648SRichard Henderson } 39681ca74648SRichard Henderson 39691ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 39701ca74648SRichard Henderson { 39711ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 39721ca74648SRichard Henderson } 39731ca74648SRichard Henderson 39741ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 39751ca74648SRichard Henderson { 39761ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 39771ca74648SRichard Henderson } 39781ca74648SRichard Henderson 39791ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3980ebe9383cSRichard Henderson { 3981ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 3982ebe9383cSRichard Henderson } 3983ebe9383cSRichard Henderson 39841ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 39851ca74648SRichard Henderson { 39861ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 39871ca74648SRichard Henderson } 39881ca74648SRichard Henderson 3989ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3990ebe9383cSRichard Henderson { 3991ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 3992ebe9383cSRichard Henderson } 3993ebe9383cSRichard Henderson 39941ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 39951ca74648SRichard Henderson { 39961ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 39971ca74648SRichard Henderson } 39981ca74648SRichard Henderson 39991ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4000ebe9383cSRichard Henderson { 4001ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 4002ebe9383cSRichard Henderson } 4003ebe9383cSRichard Henderson 40041ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 40051ca74648SRichard Henderson { 40061ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 40071ca74648SRichard Henderson } 40081ca74648SRichard Henderson 4009ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4010ebe9383cSRichard Henderson { 4011ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4012ebe9383cSRichard Henderson } 4013ebe9383cSRichard Henderson 40141ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 40151ca74648SRichard Henderson { 40161ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 40171ca74648SRichard Henderson } 40181ca74648SRichard Henderson 40191ca74648SRichard Henderson /* 40201ca74648SRichard Henderson * Float class 1 40211ca74648SRichard Henderson */ 40221ca74648SRichard Henderson 40231ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 40241ca74648SRichard Henderson { 40251ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 40261ca74648SRichard Henderson } 40271ca74648SRichard Henderson 40281ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 40291ca74648SRichard Henderson { 40301ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 40311ca74648SRichard Henderson } 40321ca74648SRichard Henderson 40331ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 40341ca74648SRichard Henderson { 40351ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 40361ca74648SRichard Henderson } 40371ca74648SRichard Henderson 40381ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 40391ca74648SRichard Henderson { 40401ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 40411ca74648SRichard Henderson } 40421ca74648SRichard Henderson 40431ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 40441ca74648SRichard Henderson { 40451ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 40461ca74648SRichard Henderson } 40471ca74648SRichard Henderson 40481ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 40491ca74648SRichard Henderson { 40501ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 40511ca74648SRichard Henderson } 40521ca74648SRichard Henderson 40531ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 40541ca74648SRichard Henderson { 40551ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 40561ca74648SRichard Henderson } 40571ca74648SRichard Henderson 40581ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 40591ca74648SRichard Henderson { 40601ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 40611ca74648SRichard Henderson } 40621ca74648SRichard Henderson 40631ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 40641ca74648SRichard Henderson { 40651ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 40661ca74648SRichard Henderson } 40671ca74648SRichard Henderson 40681ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 40691ca74648SRichard Henderson { 40701ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 40711ca74648SRichard Henderson } 40721ca74648SRichard Henderson 40731ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 40741ca74648SRichard Henderson { 40751ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 40761ca74648SRichard Henderson } 40771ca74648SRichard Henderson 40781ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 40791ca74648SRichard Henderson { 40801ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 40811ca74648SRichard Henderson } 40821ca74648SRichard Henderson 40831ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 40841ca74648SRichard Henderson { 40851ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 40861ca74648SRichard Henderson } 40871ca74648SRichard Henderson 40881ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 40891ca74648SRichard Henderson { 40901ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 40911ca74648SRichard Henderson } 40921ca74648SRichard Henderson 40931ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 40941ca74648SRichard Henderson { 40951ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 40961ca74648SRichard Henderson } 40971ca74648SRichard Henderson 40981ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 40991ca74648SRichard Henderson { 41001ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 41011ca74648SRichard Henderson } 41021ca74648SRichard Henderson 41031ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 41041ca74648SRichard Henderson { 41051ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 41061ca74648SRichard Henderson } 41071ca74648SRichard Henderson 41081ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 41091ca74648SRichard Henderson { 41101ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 41111ca74648SRichard Henderson } 41121ca74648SRichard Henderson 41131ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 41141ca74648SRichard Henderson { 41151ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 41161ca74648SRichard Henderson } 41171ca74648SRichard Henderson 41181ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 41191ca74648SRichard Henderson { 41201ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 41211ca74648SRichard Henderson } 41221ca74648SRichard Henderson 41231ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 41241ca74648SRichard Henderson { 41251ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 41261ca74648SRichard Henderson } 41271ca74648SRichard Henderson 41281ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 41291ca74648SRichard Henderson { 41301ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 41311ca74648SRichard Henderson } 41321ca74648SRichard Henderson 41331ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 41341ca74648SRichard Henderson { 41351ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 41361ca74648SRichard Henderson } 41371ca74648SRichard Henderson 41381ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 41391ca74648SRichard Henderson { 41401ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 41411ca74648SRichard Henderson } 41421ca74648SRichard Henderson 41431ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 41441ca74648SRichard Henderson { 41451ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 41461ca74648SRichard Henderson } 41471ca74648SRichard Henderson 41481ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 41491ca74648SRichard Henderson { 41501ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 41511ca74648SRichard Henderson } 41521ca74648SRichard Henderson 41531ca74648SRichard Henderson /* 41541ca74648SRichard Henderson * Float class 2 41551ca74648SRichard Henderson */ 41561ca74648SRichard Henderson 41571ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4158ebe9383cSRichard Henderson { 4159ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4160ebe9383cSRichard Henderson 4161ebe9383cSRichard Henderson nullify_over(ctx); 4162ebe9383cSRichard Henderson 41631ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 41641ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 416529dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 416629dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4167ebe9383cSRichard Henderson 4168ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4169ebe9383cSRichard Henderson 41701ca74648SRichard Henderson return nullify_end(ctx); 4171ebe9383cSRichard Henderson } 4172ebe9383cSRichard Henderson 41731ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4174ebe9383cSRichard Henderson { 4175ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4176ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4177ebe9383cSRichard Henderson 4178ebe9383cSRichard Henderson nullify_over(ctx); 4179ebe9383cSRichard Henderson 41801ca74648SRichard Henderson ta = load_frd0(a->r1); 41811ca74648SRichard Henderson tb = load_frd0(a->r2); 418229dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 418329dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4184ebe9383cSRichard Henderson 4185ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4186ebe9383cSRichard Henderson 418731234768SRichard Henderson return nullify_end(ctx); 4188ebe9383cSRichard Henderson } 4189ebe9383cSRichard Henderson 41901ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4191ebe9383cSRichard Henderson { 41926fd0c7bcSRichard Henderson TCGv_i64 t; 4193ebe9383cSRichard Henderson 4194ebe9383cSRichard Henderson nullify_over(ctx); 4195ebe9383cSRichard Henderson 4196aac0f603SRichard Henderson t = tcg_temp_new_i64(); 41976fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4198ebe9383cSRichard Henderson 41991ca74648SRichard Henderson if (a->y == 1) { 4200ebe9383cSRichard Henderson int mask; 4201ebe9383cSRichard Henderson bool inv = false; 4202ebe9383cSRichard Henderson 42031ca74648SRichard Henderson switch (a->c) { 4204ebe9383cSRichard Henderson case 0: /* simple */ 42056fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 4206ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4207ebe9383cSRichard Henderson goto done; 4208ebe9383cSRichard Henderson case 2: /* rej */ 4209ebe9383cSRichard Henderson inv = true; 4210ebe9383cSRichard Henderson /* fallthru */ 4211ebe9383cSRichard Henderson case 1: /* acc */ 4212ebe9383cSRichard Henderson mask = 0x43ff800; 4213ebe9383cSRichard Henderson break; 4214ebe9383cSRichard Henderson case 6: /* rej8 */ 4215ebe9383cSRichard Henderson inv = true; 4216ebe9383cSRichard Henderson /* fallthru */ 4217ebe9383cSRichard Henderson case 5: /* acc8 */ 4218ebe9383cSRichard Henderson mask = 0x43f8000; 4219ebe9383cSRichard Henderson break; 4220ebe9383cSRichard Henderson case 9: /* acc6 */ 4221ebe9383cSRichard Henderson mask = 0x43e0000; 4222ebe9383cSRichard Henderson break; 4223ebe9383cSRichard Henderson case 13: /* acc4 */ 4224ebe9383cSRichard Henderson mask = 0x4380000; 4225ebe9383cSRichard Henderson break; 4226ebe9383cSRichard Henderson case 17: /* acc2 */ 4227ebe9383cSRichard Henderson mask = 0x4200000; 4228ebe9383cSRichard Henderson break; 4229ebe9383cSRichard Henderson default: 42301ca74648SRichard Henderson gen_illegal(ctx); 42311ca74648SRichard Henderson return true; 4232ebe9383cSRichard Henderson } 4233ebe9383cSRichard Henderson if (inv) { 42346fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 42356fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 4236ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 4237ebe9383cSRichard Henderson } else { 42386fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 4239ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 4240ebe9383cSRichard Henderson } 42411ca74648SRichard Henderson } else { 42421ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 42431ca74648SRichard Henderson 42446fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 42451ca74648SRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 42461ca74648SRichard Henderson } 42471ca74648SRichard Henderson 4248ebe9383cSRichard Henderson done: 424931234768SRichard Henderson return nullify_end(ctx); 4250ebe9383cSRichard Henderson } 4251ebe9383cSRichard Henderson 42521ca74648SRichard Henderson /* 42531ca74648SRichard Henderson * Float class 2 42541ca74648SRichard Henderson */ 42551ca74648SRichard Henderson 42561ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4257ebe9383cSRichard Henderson { 42581ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 42591ca74648SRichard Henderson } 42601ca74648SRichard Henderson 42611ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 42621ca74648SRichard Henderson { 42631ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 42641ca74648SRichard Henderson } 42651ca74648SRichard Henderson 42661ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 42671ca74648SRichard Henderson { 42681ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 42691ca74648SRichard Henderson } 42701ca74648SRichard Henderson 42711ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 42721ca74648SRichard Henderson { 42731ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 42741ca74648SRichard Henderson } 42751ca74648SRichard Henderson 42761ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 42771ca74648SRichard Henderson { 42781ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 42791ca74648SRichard Henderson } 42801ca74648SRichard Henderson 42811ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 42821ca74648SRichard Henderson { 42831ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 42841ca74648SRichard Henderson } 42851ca74648SRichard Henderson 42861ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 42871ca74648SRichard Henderson { 42881ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 42891ca74648SRichard Henderson } 42901ca74648SRichard Henderson 42911ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 42921ca74648SRichard Henderson { 42931ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 42941ca74648SRichard Henderson } 42951ca74648SRichard Henderson 42961ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 42971ca74648SRichard Henderson { 42981ca74648SRichard Henderson TCGv_i64 x, y; 4299ebe9383cSRichard Henderson 4300ebe9383cSRichard Henderson nullify_over(ctx); 4301ebe9383cSRichard Henderson 43021ca74648SRichard Henderson x = load_frw0_i64(a->r1); 43031ca74648SRichard Henderson y = load_frw0_i64(a->r2); 43041ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 43051ca74648SRichard Henderson save_frd(a->t, x); 4306ebe9383cSRichard Henderson 430731234768SRichard Henderson return nullify_end(ctx); 4308ebe9383cSRichard Henderson } 4309ebe9383cSRichard Henderson 4310ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4311ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4312ebe9383cSRichard Henderson { 4313ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4314ebe9383cSRichard Henderson } 4315ebe9383cSRichard Henderson 4316b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4317ebe9383cSRichard Henderson { 4318b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4319b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4320b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4321b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4322b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4323ebe9383cSRichard Henderson 4324ebe9383cSRichard Henderson nullify_over(ctx); 4325ebe9383cSRichard Henderson 4326ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4327ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4328ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4329ebe9383cSRichard Henderson 433031234768SRichard Henderson return nullify_end(ctx); 4331ebe9383cSRichard Henderson } 4332ebe9383cSRichard Henderson 4333b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4334b1e2af57SRichard Henderson { 4335b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4336b1e2af57SRichard Henderson } 4337b1e2af57SRichard Henderson 4338b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4339b1e2af57SRichard Henderson { 4340b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4341b1e2af57SRichard Henderson } 4342b1e2af57SRichard Henderson 4343b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4344b1e2af57SRichard Henderson { 4345b1e2af57SRichard Henderson nullify_over(ctx); 4346b1e2af57SRichard Henderson 4347b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4348b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4349b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4350b1e2af57SRichard Henderson 4351b1e2af57SRichard Henderson return nullify_end(ctx); 4352b1e2af57SRichard Henderson } 4353b1e2af57SRichard Henderson 4354b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4355b1e2af57SRichard Henderson { 4356b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4357b1e2af57SRichard Henderson } 4358b1e2af57SRichard Henderson 4359b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4360b1e2af57SRichard Henderson { 4361b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4362b1e2af57SRichard Henderson } 4363b1e2af57SRichard Henderson 4364c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4365ebe9383cSRichard Henderson { 4366c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4367ebe9383cSRichard Henderson 4368ebe9383cSRichard Henderson nullify_over(ctx); 4369c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4370c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4371c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4372ebe9383cSRichard Henderson 4373c3bad4f8SRichard Henderson if (a->neg) { 4374ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4375ebe9383cSRichard Henderson } else { 4376ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4377ebe9383cSRichard Henderson } 4378ebe9383cSRichard Henderson 4379c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 438031234768SRichard Henderson return nullify_end(ctx); 4381ebe9383cSRichard Henderson } 4382ebe9383cSRichard Henderson 4383c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4384ebe9383cSRichard Henderson { 4385c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4386ebe9383cSRichard Henderson 4387ebe9383cSRichard Henderson nullify_over(ctx); 4388c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4389c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4390c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4391ebe9383cSRichard Henderson 4392c3bad4f8SRichard Henderson if (a->neg) { 4393ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4394ebe9383cSRichard Henderson } else { 4395ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4396ebe9383cSRichard Henderson } 4397ebe9383cSRichard Henderson 4398c3bad4f8SRichard Henderson save_frd(a->t, x); 439931234768SRichard Henderson return nullify_end(ctx); 4400ebe9383cSRichard Henderson } 4401ebe9383cSRichard Henderson 440215da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a) 440315da177bSSven Schnelle { 4404cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4405cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4406cf6b28d4SHelge Deller if (a->i == 0x100) { 4407cf6b28d4SHelge Deller /* emulate PDC BTLB, called by SeaBIOS-hppa */ 4408ad75a51eSRichard Henderson nullify_over(ctx); 4409ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4410cf6b28d4SHelge Deller return nullify_end(ctx); 441115da177bSSven Schnelle } 4412ad75a51eSRichard Henderson #endif 4413ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4414ad75a51eSRichard Henderson return true; 4415ad75a51eSRichard Henderson } 441615da177bSSven Schnelle 4417b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 441861766fe9SRichard Henderson { 441951b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4420f764718dSRichard Henderson int bound; 442161766fe9SRichard Henderson 442251b061fbSRichard Henderson ctx->cs = cs; 4423494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4424bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 44253d68ee7bSRichard Henderson 44263d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4427c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 44283d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 4429c01e5dfbSHelge Deller ctx->iaoq_f = ctx->base.pc_first | ctx->privilege; 4430c01e5dfbSHelge Deller ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege; 4431217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4432c301f34eSRichard Henderson #else 4433494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4434bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4435bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4436bb67ec32SRichard Henderson : MMU_PHYS_IDX); 44373d68ee7bSRichard Henderson 4438c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4439c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4440c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4441c301f34eSRichard Henderson int32_t diff = cs_base; 4442c301f34eSRichard Henderson 4443c301f34eSRichard Henderson ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4444c301f34eSRichard Henderson ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); 4445c301f34eSRichard Henderson #endif 444651b061fbSRichard Henderson ctx->iaoq_n = -1; 4447f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 444861766fe9SRichard Henderson 4449a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4450a4db4a78SRichard Henderson 44513d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 44523d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4453b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 445461766fe9SRichard Henderson } 445561766fe9SRichard Henderson 445651b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 445751b061fbSRichard Henderson { 445851b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 445961766fe9SRichard Henderson 44603d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 446151b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 446251b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4463494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 446451b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 446551b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4466129e9cc3SRichard Henderson } 446751b061fbSRichard Henderson ctx->null_lab = NULL; 446861766fe9SRichard Henderson } 446961766fe9SRichard Henderson 447051b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 447151b061fbSRichard Henderson { 447251b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 447351b061fbSRichard Henderson 4474f5b5c857SRichard Henderson tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0); 4475f5b5c857SRichard Henderson ctx->insn_start = tcg_last_op(); 447651b061fbSRichard Henderson } 447751b061fbSRichard Henderson 447851b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 447951b061fbSRichard Henderson { 448051b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4481b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 448251b061fbSRichard Henderson DisasJumpType ret; 448351b061fbSRichard Henderson 448451b061fbSRichard Henderson /* Execute one insn. */ 4485ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4486c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 448731234768SRichard Henderson do_page_zero(ctx); 448831234768SRichard Henderson ret = ctx->base.is_jmp; 4489869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4490ba1d0b44SRichard Henderson } else 4491ba1d0b44SRichard Henderson #endif 4492ba1d0b44SRichard Henderson { 449361766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 449461766fe9SRichard Henderson the page permissions for execute. */ 44954e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 449661766fe9SRichard Henderson 449761766fe9SRichard Henderson /* Set up the IA queue for the next insn. 449861766fe9SRichard Henderson This will be overwritten by a branch. */ 449951b061fbSRichard Henderson if (ctx->iaoq_b == -1) { 450051b061fbSRichard Henderson ctx->iaoq_n = -1; 4501aac0f603SRichard Henderson ctx->iaoq_n_var = tcg_temp_new_i64(); 45026fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 450361766fe9SRichard Henderson } else { 450451b061fbSRichard Henderson ctx->iaoq_n = ctx->iaoq_b + 4; 4505f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 450661766fe9SRichard Henderson } 450761766fe9SRichard Henderson 450851b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 450951b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4510869051eaSRichard Henderson ret = DISAS_NEXT; 4511129e9cc3SRichard Henderson } else { 45121a19da0dSRichard Henderson ctx->insn = insn; 451331274b46SRichard Henderson if (!decode(ctx, insn)) { 451431274b46SRichard Henderson gen_illegal(ctx); 451531274b46SRichard Henderson } 451631234768SRichard Henderson ret = ctx->base.is_jmp; 451751b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4518129e9cc3SRichard Henderson } 451961766fe9SRichard Henderson } 452061766fe9SRichard Henderson 45213d68ee7bSRichard Henderson /* Advance the insn queue. Note that this check also detects 45223d68ee7bSRichard Henderson a priority change within the instruction queue. */ 452351b061fbSRichard Henderson if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 4524c301f34eSRichard Henderson if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 4525c301f34eSRichard Henderson && use_goto_tb(ctx, ctx->iaoq_b) 4526c301f34eSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4527c301f34eSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 452851b061fbSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 452951b061fbSRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 453031234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_NORETURN; 4531129e9cc3SRichard Henderson } else { 453231234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE; 453361766fe9SRichard Henderson } 4534129e9cc3SRichard Henderson } 453551b061fbSRichard Henderson ctx->iaoq_f = ctx->iaoq_b; 453651b061fbSRichard Henderson ctx->iaoq_b = ctx->iaoq_n; 4537c301f34eSRichard Henderson ctx->base.pc_next += 4; 453861766fe9SRichard Henderson 4539c5d0aec2SRichard Henderson switch (ret) { 4540c5d0aec2SRichard Henderson case DISAS_NORETURN: 4541c5d0aec2SRichard Henderson case DISAS_IAQ_N_UPDATED: 4542c5d0aec2SRichard Henderson break; 4543c5d0aec2SRichard Henderson 4544c5d0aec2SRichard Henderson case DISAS_NEXT: 4545c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE: 4546c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 454751b061fbSRichard Henderson if (ctx->iaoq_f == -1) { 4548a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b); 4549741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 4550c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY 4551c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 4552c301f34eSRichard Henderson #endif 455351b061fbSRichard Henderson nullify_save(ctx); 4554c5d0aec2SRichard Henderson ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT 4555c5d0aec2SRichard Henderson ? DISAS_EXIT 4556c5d0aec2SRichard Henderson : DISAS_IAQ_N_UPDATED); 455751b061fbSRichard Henderson } else if (ctx->iaoq_b == -1) { 4558a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var); 455961766fe9SRichard Henderson } 4560c5d0aec2SRichard Henderson break; 4561c5d0aec2SRichard Henderson 4562c5d0aec2SRichard Henderson default: 4563c5d0aec2SRichard Henderson g_assert_not_reached(); 4564c5d0aec2SRichard Henderson } 456561766fe9SRichard Henderson } 456661766fe9SRichard Henderson 456751b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 456851b061fbSRichard Henderson { 456951b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4570e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 457151b061fbSRichard Henderson 4572e1b5a5edSRichard Henderson switch (is_jmp) { 4573869051eaSRichard Henderson case DISAS_NORETURN: 457461766fe9SRichard Henderson break; 457551b061fbSRichard Henderson case DISAS_TOO_MANY: 4576869051eaSRichard Henderson case DISAS_IAQ_N_STALE: 4577e1b5a5edSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4578741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 4579741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 458051b061fbSRichard Henderson nullify_save(ctx); 458161766fe9SRichard Henderson /* FALLTHRU */ 4582869051eaSRichard Henderson case DISAS_IAQ_N_UPDATED: 45838532a14eSRichard Henderson if (is_jmp != DISAS_IAQ_N_STALE_EXIT) { 45847f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 45858532a14eSRichard Henderson break; 458661766fe9SRichard Henderson } 4587c5d0aec2SRichard Henderson /* FALLTHRU */ 4588c5d0aec2SRichard Henderson case DISAS_EXIT: 4589c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 459061766fe9SRichard Henderson break; 459161766fe9SRichard Henderson default: 459251b061fbSRichard Henderson g_assert_not_reached(); 459361766fe9SRichard Henderson } 459451b061fbSRichard Henderson } 459561766fe9SRichard Henderson 45968eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 45978eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 459851b061fbSRichard Henderson { 4599c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 460061766fe9SRichard Henderson 4601ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4602ba1d0b44SRichard Henderson switch (pc) { 46037ad439dfSRichard Henderson case 0x00: 46048eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4605ba1d0b44SRichard Henderson return; 46067ad439dfSRichard Henderson case 0xb0: 46078eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4608ba1d0b44SRichard Henderson return; 46097ad439dfSRichard Henderson case 0xe0: 46108eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4611ba1d0b44SRichard Henderson return; 46127ad439dfSRichard Henderson case 0x100: 46138eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4614ba1d0b44SRichard Henderson return; 46157ad439dfSRichard Henderson } 4616ba1d0b44SRichard Henderson #endif 4617ba1d0b44SRichard Henderson 46188eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 46198eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 462061766fe9SRichard Henderson } 462151b061fbSRichard Henderson 462251b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 462351b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 462451b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 462551b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 462651b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 462751b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 462851b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 462951b061fbSRichard Henderson }; 463051b061fbSRichard Henderson 4631597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 4632306c8721SRichard Henderson target_ulong pc, void *host_pc) 463351b061fbSRichard Henderson { 463451b061fbSRichard Henderson DisasContext ctx; 4635306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 463661766fe9SRichard Henderson } 4637