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; 4761766fe9SRichard Henderson 48c53e401eSRichard Henderson uint64_t iaoq_f; 49c53e401eSRichard Henderson uint64_t iaoq_b; 50c53e401eSRichard Henderson uint64_t iaoq_n; 516fd0c7bcSRichard Henderson TCGv_i64 iaoq_n_var; 5261766fe9SRichard Henderson 5361766fe9SRichard Henderson DisasCond null_cond; 5461766fe9SRichard Henderson TCGLabel *null_lab; 5561766fe9SRichard Henderson 56a4db4a78SRichard Henderson TCGv_i64 zero; 57a4db4a78SRichard Henderson 581a19da0dSRichard Henderson uint32_t insn; 59494737b7SRichard Henderson uint32_t tb_flags; 603d68ee7bSRichard Henderson int mmu_idx; 613d68ee7bSRichard Henderson int privilege; 6261766fe9SRichard Henderson bool psw_n_nonzero; 63bd6243a3SRichard Henderson bool is_pa20; 64217d1a5eSRichard Henderson 65217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 66217d1a5eSRichard Henderson MemOp unalign; 67217d1a5eSRichard Henderson #endif 6861766fe9SRichard Henderson } DisasContext; 6961766fe9SRichard Henderson 70217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 71217d1a5eSRichard Henderson #define UNALIGN(C) (C)->unalign 72217d1a5eSRichard Henderson #else 732d4afb03SRichard Henderson #define UNALIGN(C) MO_ALIGN 74217d1a5eSRichard Henderson #endif 75217d1a5eSRichard Henderson 76e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 77451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val) 78e36f27efSRichard Henderson { 79e36f27efSRichard Henderson if (val & PSW_SM_E) { 80e36f27efSRichard Henderson val = (val & ~PSW_SM_E) | PSW_E; 81e36f27efSRichard Henderson } 82e36f27efSRichard Henderson if (val & PSW_SM_W) { 83e36f27efSRichard Henderson val = (val & ~PSW_SM_W) | PSW_W; 84e36f27efSRichard Henderson } 85e36f27efSRichard Henderson return val; 86e36f27efSRichard Henderson } 87e36f27efSRichard Henderson 88deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base. */ 89451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val) 90deee69a1SRichard Henderson { 91deee69a1SRichard Henderson return ~val; 92deee69a1SRichard Henderson } 93deee69a1SRichard Henderson 941cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value 951cd012a5SRichard Henderson we use for the final M. */ 96451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val) 971cd012a5SRichard Henderson { 981cd012a5SRichard Henderson return val & 2 ? (val & 1 ? -1 : 1) : 0; 991cd012a5SRichard Henderson } 1001cd012a5SRichard Henderson 101740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify. */ 102451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val) 103740038d7SRichard Henderson { 104740038d7SRichard Henderson return val ? 1 : -1; 105740038d7SRichard Henderson } 106740038d7SRichard Henderson 107451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val) 108740038d7SRichard Henderson { 109740038d7SRichard Henderson return val ? -1 : 1; 110740038d7SRichard Henderson } 111740038d7SRichard Henderson 112740038d7SRichard Henderson /* Used for branch targets and fp memory ops. */ 113451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val) 11401afb7beSRichard Henderson { 11501afb7beSRichard Henderson return val << 2; 11601afb7beSRichard Henderson } 11701afb7beSRichard Henderson 118740038d7SRichard Henderson /* Used for fp memory ops. */ 119451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val) 120740038d7SRichard Henderson { 121740038d7SRichard Henderson return val << 3; 122740038d7SRichard Henderson } 123740038d7SRichard Henderson 1240588e061SRichard Henderson /* Used for assemble_21. */ 125451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val) 1260588e061SRichard Henderson { 1270588e061SRichard Henderson return val << 11; 1280588e061SRichard Henderson } 1290588e061SRichard Henderson 13072ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val) 13172ae4f2bSRichard Henderson { 13272ae4f2bSRichard Henderson /* 13372ae4f2bSRichard Henderson * Officially, 32 * x + 32 - y. 13472ae4f2bSRichard Henderson * Here, x is already in bit 5, and y is [4:0]. 13572ae4f2bSRichard Henderson * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1, 13672ae4f2bSRichard Henderson * with the overflow from bit 4 summing with x. 13772ae4f2bSRichard Henderson */ 13872ae4f2bSRichard Henderson return (val ^ 31) + 1; 13972ae4f2bSRichard Henderson } 14072ae4f2bSRichard Henderson 141c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */ 142c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val) 143c65c3ee1SRichard Henderson { 144c65c3ee1SRichard Henderson return val ? val : 4; /* 0 == "*<<" */ 145c65c3ee1SRichard Henderson } 146c65c3ee1SRichard Henderson 14701afb7beSRichard Henderson 14840f9f908SRichard Henderson /* Include the auto-generated decoder. */ 149abff1abfSPaolo Bonzini #include "decode-insns.c.inc" 15040f9f908SRichard Henderson 15161766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 15261766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 153869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 15461766fe9SRichard Henderson 15561766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 15661766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 157869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 15861766fe9SRichard Henderson 159e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 160e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 161e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 162c5d0aec2SRichard Henderson #define DISAS_EXIT DISAS_TARGET_3 163e1b5a5edSRichard Henderson 16461766fe9SRichard Henderson /* global register indexes */ 1656fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32]; 16633423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 167494737b7SRichard Henderson static TCGv_i64 cpu_srH; 1686fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f; 1696fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b; 170c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 171c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 1726fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar; 1736fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n; 1746fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v; 1756fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb; 1766fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb; 17761766fe9SRichard Henderson 17861766fe9SRichard Henderson void hppa_translate_init(void) 17961766fe9SRichard Henderson { 18061766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 18161766fe9SRichard Henderson 1826fd0c7bcSRichard Henderson typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 18361766fe9SRichard Henderson static const GlobalVar vars[] = { 18435136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 18561766fe9SRichard Henderson DEF_VAR(psw_n), 18661766fe9SRichard Henderson DEF_VAR(psw_v), 18761766fe9SRichard Henderson DEF_VAR(psw_cb), 18861766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 18961766fe9SRichard Henderson DEF_VAR(iaoq_f), 19061766fe9SRichard Henderson DEF_VAR(iaoq_b), 19161766fe9SRichard Henderson }; 19261766fe9SRichard Henderson 19361766fe9SRichard Henderson #undef DEF_VAR 19461766fe9SRichard Henderson 19561766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 19661766fe9SRichard Henderson static const char gr_names[32][4] = { 19761766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 19861766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 19961766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 20061766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 20161766fe9SRichard Henderson }; 20233423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 203494737b7SRichard Henderson static const char sr_names[5][4] = { 204494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 20533423472SRichard Henderson }; 20661766fe9SRichard Henderson 20761766fe9SRichard Henderson int i; 20861766fe9SRichard Henderson 209f764718dSRichard Henderson cpu_gr[0] = NULL; 21061766fe9SRichard Henderson for (i = 1; i < 32; i++) { 211ad75a51eSRichard Henderson cpu_gr[i] = tcg_global_mem_new(tcg_env, 21261766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 21361766fe9SRichard Henderson gr_names[i]); 21461766fe9SRichard Henderson } 21533423472SRichard Henderson for (i = 0; i < 4; i++) { 216ad75a51eSRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 21733423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 21833423472SRichard Henderson sr_names[i]); 21933423472SRichard Henderson } 220ad75a51eSRichard Henderson cpu_srH = tcg_global_mem_new_i64(tcg_env, 221494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 222494737b7SRichard Henderson sr_names[4]); 22361766fe9SRichard Henderson 22461766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 22561766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 226ad75a51eSRichard Henderson *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 22761766fe9SRichard Henderson } 228c301f34eSRichard Henderson 229ad75a51eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 230c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 231c301f34eSRichard Henderson "iasq_f"); 232ad75a51eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 233c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 234c301f34eSRichard Henderson "iasq_b"); 23561766fe9SRichard Henderson } 23661766fe9SRichard Henderson 237129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 238129e9cc3SRichard Henderson { 239f764718dSRichard Henderson return (DisasCond){ 240f764718dSRichard Henderson .c = TCG_COND_NEVER, 241f764718dSRichard Henderson .a0 = NULL, 242f764718dSRichard Henderson .a1 = NULL, 243f764718dSRichard Henderson }; 244129e9cc3SRichard Henderson } 245129e9cc3SRichard Henderson 246df0232feSRichard Henderson static DisasCond cond_make_t(void) 247df0232feSRichard Henderson { 248df0232feSRichard Henderson return (DisasCond){ 249df0232feSRichard Henderson .c = TCG_COND_ALWAYS, 250df0232feSRichard Henderson .a0 = NULL, 251df0232feSRichard Henderson .a1 = NULL, 252df0232feSRichard Henderson }; 253df0232feSRichard Henderson } 254df0232feSRichard Henderson 255129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 256129e9cc3SRichard Henderson { 257f764718dSRichard Henderson return (DisasCond){ 258f764718dSRichard Henderson .c = TCG_COND_NE, 259f764718dSRichard Henderson .a0 = cpu_psw_n, 2606fd0c7bcSRichard Henderson .a1 = tcg_constant_i64(0) 261f764718dSRichard Henderson }; 262129e9cc3SRichard Henderson } 263129e9cc3SRichard Henderson 2646fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 265b47a4a02SSven Schnelle { 266b47a4a02SSven Schnelle assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 2674fe9533aSRichard Henderson return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 2684fe9533aSRichard Henderson } 2694fe9533aSRichard Henderson 2706fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0) 2714fe9533aSRichard Henderson { 2726fd0c7bcSRichard Henderson return cond_make_tmp(c, a0, tcg_constant_i64(0)); 273b47a4a02SSven Schnelle } 274b47a4a02SSven Schnelle 2756fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0) 276129e9cc3SRichard Henderson { 277aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2786fd0c7bcSRichard Henderson tcg_gen_mov_i64(tmp, a0); 279b47a4a02SSven Schnelle return cond_make_0_tmp(c, tmp); 280129e9cc3SRichard Henderson } 281129e9cc3SRichard Henderson 2826fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 283129e9cc3SRichard Henderson { 284aac0f603SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 285aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 286129e9cc3SRichard Henderson 2876fd0c7bcSRichard Henderson tcg_gen_mov_i64(t0, a0); 2886fd0c7bcSRichard Henderson tcg_gen_mov_i64(t1, a1); 2894fe9533aSRichard Henderson return cond_make_tmp(c, t0, t1); 290129e9cc3SRichard Henderson } 291129e9cc3SRichard Henderson 292129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 293129e9cc3SRichard Henderson { 294129e9cc3SRichard Henderson switch (cond->c) { 295129e9cc3SRichard Henderson default: 296f764718dSRichard Henderson cond->a0 = NULL; 297f764718dSRichard Henderson cond->a1 = NULL; 298129e9cc3SRichard Henderson /* fallthru */ 299129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 300129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 301129e9cc3SRichard Henderson break; 302129e9cc3SRichard Henderson case TCG_COND_NEVER: 303129e9cc3SRichard Henderson break; 304129e9cc3SRichard Henderson } 305129e9cc3SRichard Henderson } 306129e9cc3SRichard Henderson 3076fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 30861766fe9SRichard Henderson { 30961766fe9SRichard Henderson if (reg == 0) { 310bc3da3cfSRichard Henderson return ctx->zero; 31161766fe9SRichard Henderson } else { 31261766fe9SRichard Henderson return cpu_gr[reg]; 31361766fe9SRichard Henderson } 31461766fe9SRichard Henderson } 31561766fe9SRichard Henderson 3166fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 31761766fe9SRichard Henderson { 318129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 319aac0f603SRichard Henderson return tcg_temp_new_i64(); 32061766fe9SRichard Henderson } else { 32161766fe9SRichard Henderson return cpu_gr[reg]; 32261766fe9SRichard Henderson } 32361766fe9SRichard Henderson } 32461766fe9SRichard Henderson 3256fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 326129e9cc3SRichard Henderson { 327129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 3286fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 329129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 330129e9cc3SRichard Henderson } else { 3316fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 332129e9cc3SRichard Henderson } 333129e9cc3SRichard Henderson } 334129e9cc3SRichard Henderson 3356fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 336129e9cc3SRichard Henderson { 337129e9cc3SRichard Henderson if (reg != 0) { 338129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 339129e9cc3SRichard Henderson } 340129e9cc3SRichard Henderson } 341129e9cc3SRichard Henderson 342e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 34396d6407fSRichard Henderson # define HI_OFS 0 34496d6407fSRichard Henderson # define LO_OFS 4 34596d6407fSRichard Henderson #else 34696d6407fSRichard Henderson # define HI_OFS 4 34796d6407fSRichard Henderson # define LO_OFS 0 34896d6407fSRichard Henderson #endif 34996d6407fSRichard Henderson 35096d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 35196d6407fSRichard Henderson { 35296d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 353ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 35496d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 35596d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 35696d6407fSRichard Henderson return ret; 35796d6407fSRichard Henderson } 35896d6407fSRichard Henderson 359ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 360ebe9383cSRichard Henderson { 361ebe9383cSRichard Henderson if (rt == 0) { 3620992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 3630992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 3640992a930SRichard Henderson return ret; 365ebe9383cSRichard Henderson } else { 366ebe9383cSRichard Henderson return load_frw_i32(rt); 367ebe9383cSRichard Henderson } 368ebe9383cSRichard Henderson } 369ebe9383cSRichard Henderson 370ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 371ebe9383cSRichard Henderson { 372ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 3730992a930SRichard Henderson if (rt == 0) { 3740992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 3750992a930SRichard Henderson } else { 376ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 377ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 378ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 379ebe9383cSRichard Henderson } 3800992a930SRichard Henderson return ret; 381ebe9383cSRichard Henderson } 382ebe9383cSRichard Henderson 38396d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 38496d6407fSRichard Henderson { 385ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 38696d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 38796d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 38896d6407fSRichard Henderson } 38996d6407fSRichard Henderson 39096d6407fSRichard Henderson #undef HI_OFS 39196d6407fSRichard Henderson #undef LO_OFS 39296d6407fSRichard Henderson 39396d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 39496d6407fSRichard Henderson { 39596d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 396ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 39796d6407fSRichard Henderson return ret; 39896d6407fSRichard Henderson } 39996d6407fSRichard Henderson 400ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 401ebe9383cSRichard Henderson { 402ebe9383cSRichard Henderson if (rt == 0) { 4030992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4040992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4050992a930SRichard Henderson return ret; 406ebe9383cSRichard Henderson } else { 407ebe9383cSRichard Henderson return load_frd(rt); 408ebe9383cSRichard Henderson } 409ebe9383cSRichard Henderson } 410ebe9383cSRichard Henderson 41196d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 41296d6407fSRichard Henderson { 413ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 41496d6407fSRichard Henderson } 41596d6407fSRichard Henderson 41633423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 41733423472SRichard Henderson { 41833423472SRichard Henderson #ifdef CONFIG_USER_ONLY 41933423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 42033423472SRichard Henderson #else 42133423472SRichard Henderson if (reg < 4) { 42233423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 423494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 424494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 42533423472SRichard Henderson } else { 426ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 42733423472SRichard Henderson } 42833423472SRichard Henderson #endif 42933423472SRichard Henderson } 43033423472SRichard Henderson 431129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 432129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 433129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 434129e9cc3SRichard Henderson { 435129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 436129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 437129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 438129e9cc3SRichard Henderson 439129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 440129e9cc3SRichard Henderson 441129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 4426e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 443aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 4446fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 445129e9cc3SRichard Henderson } 446129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 447129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 448129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 449129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 450129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 4516fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 452129e9cc3SRichard Henderson } 453129e9cc3SRichard Henderson 4546fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 455129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 456129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 457129e9cc3SRichard Henderson } 458129e9cc3SRichard Henderson } 459129e9cc3SRichard Henderson 460129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 461129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 462129e9cc3SRichard Henderson { 463129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 464129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 4656fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 466129e9cc3SRichard Henderson } 467129e9cc3SRichard Henderson return; 468129e9cc3SRichard Henderson } 4696e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 4706fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 471129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 472129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 473129e9cc3SRichard Henderson } 474129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 475129e9cc3SRichard Henderson } 476129e9cc3SRichard Henderson 477129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 478129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 479129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 480129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 481129e9cc3SRichard Henderson { 482129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 4836fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 484129e9cc3SRichard Henderson } 485129e9cc3SRichard Henderson } 486129e9cc3SRichard Henderson 487129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 48840f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 48940f9f908SRichard Henderson it may be tail-called from a translate function. */ 49031234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 491129e9cc3SRichard Henderson { 492129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 49331234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 494129e9cc3SRichard Henderson 495f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 496f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 497f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 498f49b3537SRichard Henderson 499129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 500129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 501129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 502129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 50331234768SRichard Henderson return true; 504129e9cc3SRichard Henderson } 505129e9cc3SRichard Henderson ctx->null_lab = NULL; 506129e9cc3SRichard Henderson 507129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 508129e9cc3SRichard Henderson /* The next instruction will be unconditional, 509129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 510129e9cc3SRichard Henderson gen_set_label(null_lab); 511129e9cc3SRichard Henderson } else { 512129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 513129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 514129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 515129e9cc3SRichard Henderson label we have the proper value in place. */ 516129e9cc3SRichard Henderson nullify_save(ctx); 517129e9cc3SRichard Henderson gen_set_label(null_lab); 518129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 519129e9cc3SRichard Henderson } 520869051eaSRichard Henderson if (status == DISAS_NORETURN) { 52131234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 522129e9cc3SRichard Henderson } 52331234768SRichard Henderson return true; 524129e9cc3SRichard Henderson } 525129e9cc3SRichard Henderson 526c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx) 527698240d1SRichard Henderson { 528698240d1SRichard Henderson return (ctx->tb_flags & PSW_W 529698240d1SRichard Henderson ? MAKE_64BIT_MASK(0, 62) 530698240d1SRichard Henderson : MAKE_64BIT_MASK(0, 32)); 531698240d1SRichard Henderson } 532698240d1SRichard Henderson 5336fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 5346fd0c7bcSRichard Henderson uint64_t ival, TCGv_i64 vval) 53561766fe9SRichard Henderson { 536c53e401eSRichard Henderson uint64_t mask = gva_offset_mask(ctx); 537f13bf343SRichard Henderson 538f13bf343SRichard Henderson if (ival != -1) { 5396fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, ival & mask); 540f13bf343SRichard Henderson return; 541f13bf343SRichard Henderson } 542f13bf343SRichard Henderson tcg_debug_assert(vval != NULL); 543f13bf343SRichard Henderson 544f13bf343SRichard Henderson /* 545f13bf343SRichard Henderson * We know that the IAOQ is already properly masked. 546f13bf343SRichard Henderson * This optimization is primarily for "iaoq_f = iaoq_b". 547f13bf343SRichard Henderson */ 548f13bf343SRichard Henderson if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) { 5496fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, vval); 55061766fe9SRichard Henderson } else { 5516fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, vval, mask); 55261766fe9SRichard Henderson } 55361766fe9SRichard Henderson } 55461766fe9SRichard Henderson 555c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp) 55661766fe9SRichard Henderson { 55761766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 55861766fe9SRichard Henderson } 55961766fe9SRichard Henderson 56061766fe9SRichard Henderson static void gen_excp_1(int exception) 56161766fe9SRichard Henderson { 562ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 56361766fe9SRichard Henderson } 56461766fe9SRichard Henderson 56531234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 56661766fe9SRichard Henderson { 567741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 568741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 569129e9cc3SRichard Henderson nullify_save(ctx); 57061766fe9SRichard Henderson gen_excp_1(exception); 57131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 57261766fe9SRichard Henderson } 57361766fe9SRichard Henderson 57431234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 5751a19da0dSRichard Henderson { 57631234768SRichard Henderson nullify_over(ctx); 5776fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 578ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 57931234768SRichard Henderson gen_excp(ctx, exc); 58031234768SRichard Henderson return nullify_end(ctx); 5811a19da0dSRichard Henderson } 5821a19da0dSRichard Henderson 58331234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 58461766fe9SRichard Henderson { 58531234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 58661766fe9SRichard Henderson } 58761766fe9SRichard Henderson 58840f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 58940f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 59040f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 59140f9f908SRichard Henderson #else 592e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 593e1b5a5edSRichard Henderson do { \ 594e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 59531234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 596e1b5a5edSRichard Henderson } \ 597e1b5a5edSRichard Henderson } while (0) 59840f9f908SRichard Henderson #endif 599e1b5a5edSRichard Henderson 600c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest) 60161766fe9SRichard Henderson { 60257f91498SRichard Henderson return translator_use_goto_tb(&ctx->base, dest); 60361766fe9SRichard Henderson } 60461766fe9SRichard Henderson 605129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 606129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 607129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 608129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 609129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 610129e9cc3SRichard Henderson { 611129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 612129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 613129e9cc3SRichard Henderson } 614129e9cc3SRichard Henderson 61561766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 616c53e401eSRichard Henderson uint64_t f, uint64_t b) 61761766fe9SRichard Henderson { 61861766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 61961766fe9SRichard Henderson tcg_gen_goto_tb(which); 620a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL); 621a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL); 62207ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 62361766fe9SRichard Henderson } else { 624741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b); 625741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var); 6267f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 62761766fe9SRichard Henderson } 62861766fe9SRichard Henderson } 62961766fe9SRichard Henderson 630b47a4a02SSven Schnelle static bool cond_need_sv(int c) 631b47a4a02SSven Schnelle { 632b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 633b47a4a02SSven Schnelle } 634b47a4a02SSven Schnelle 635b47a4a02SSven Schnelle static bool cond_need_cb(int c) 636b47a4a02SSven Schnelle { 637b47a4a02SSven Schnelle return c == 4 || c == 5; 638b47a4a02SSven Schnelle } 639b47a4a02SSven Schnelle 6406fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */ 64172ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d) 64272ca8753SRichard Henderson { 643c53e401eSRichard Henderson return !(ctx->is_pa20 && d); 64472ca8753SRichard Henderson } 64572ca8753SRichard Henderson 646b47a4a02SSven Schnelle /* 647b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 648b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 649b47a4a02SSven Schnelle */ 650b2167459SRichard Henderson 651a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 6526fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv) 653b2167459SRichard Henderson { 654b2167459SRichard Henderson DisasCond cond; 6556fd0c7bcSRichard Henderson TCGv_i64 tmp; 656b2167459SRichard Henderson 657b2167459SRichard Henderson switch (cf >> 1) { 658b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 659b2167459SRichard Henderson cond = cond_make_f(); 660b2167459SRichard Henderson break; 661b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 662a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 663aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6646fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 665a751eb31SRichard Henderson res = tmp; 666a751eb31SRichard Henderson } 667b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 668b2167459SRichard Henderson break; 669b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 670aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6716fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 672a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 6736fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, tmp); 674a751eb31SRichard Henderson } 675b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_LT, tmp); 676b2167459SRichard Henderson break; 677b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 678b47a4a02SSven Schnelle /* 679b47a4a02SSven Schnelle * Simplify: 680b47a4a02SSven Schnelle * (N ^ V) | Z 681b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 682b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 683b47a4a02SSven Schnelle * (~(res ^ sv) >= 0) | !res 684b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31) | !res 685b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31 & res) 686b47a4a02SSven Schnelle */ 687aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6886fd0c7bcSRichard Henderson tcg_gen_eqv_i64(tmp, res, sv); 689a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 6906fd0c7bcSRichard Henderson tcg_gen_sextract_i64(tmp, tmp, 31, 1); 6916fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 6926fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 693a751eb31SRichard Henderson } else { 6946fd0c7bcSRichard Henderson tcg_gen_sari_i64(tmp, tmp, 63); 6956fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 696a751eb31SRichard Henderson } 697b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 698b2167459SRichard Henderson break; 699b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 700a751eb31SRichard Henderson /* Only bit 0 of cb_msb is ever set. */ 701b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 702b2167459SRichard Henderson break; 703b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 704aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7056fd0c7bcSRichard Henderson tcg_gen_neg_i64(tmp, cb_msb); 7066fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 707a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7086fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 709a751eb31SRichard Henderson } 710b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 711b2167459SRichard Henderson break; 712b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 713a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 714aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7156fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, sv); 716a751eb31SRichard Henderson sv = tmp; 717a751eb31SRichard Henderson } 718b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 719b2167459SRichard Henderson break; 720b2167459SRichard Henderson case 7: /* OD / EV */ 721aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7226fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, res, 1); 723b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_NE, tmp); 724b2167459SRichard Henderson break; 725b2167459SRichard Henderson default: 726b2167459SRichard Henderson g_assert_not_reached(); 727b2167459SRichard Henderson } 728b2167459SRichard Henderson if (cf & 1) { 729b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 730b2167459SRichard Henderson } 731b2167459SRichard Henderson 732b2167459SRichard Henderson return cond; 733b2167459SRichard Henderson } 734b2167459SRichard Henderson 735b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 736b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 737b2167459SRichard Henderson deleted as unused. */ 738b2167459SRichard Henderson 7394fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 7406fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 7416fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 742b2167459SRichard Henderson { 7434fe9533aSRichard Henderson TCGCond tc; 7444fe9533aSRichard Henderson bool ext_uns; 745b2167459SRichard Henderson 746b2167459SRichard Henderson switch (cf >> 1) { 747b2167459SRichard Henderson case 1: /* = / <> */ 7484fe9533aSRichard Henderson tc = TCG_COND_EQ; 7494fe9533aSRichard Henderson ext_uns = true; 750b2167459SRichard Henderson break; 751b2167459SRichard Henderson case 2: /* < / >= */ 7524fe9533aSRichard Henderson tc = TCG_COND_LT; 7534fe9533aSRichard Henderson ext_uns = false; 754b2167459SRichard Henderson break; 755b2167459SRichard Henderson case 3: /* <= / > */ 7564fe9533aSRichard Henderson tc = TCG_COND_LE; 7574fe9533aSRichard Henderson ext_uns = false; 758b2167459SRichard Henderson break; 759b2167459SRichard Henderson case 4: /* << / >>= */ 7604fe9533aSRichard Henderson tc = TCG_COND_LTU; 7614fe9533aSRichard Henderson ext_uns = true; 762b2167459SRichard Henderson break; 763b2167459SRichard Henderson case 5: /* <<= / >> */ 7644fe9533aSRichard Henderson tc = TCG_COND_LEU; 7654fe9533aSRichard Henderson ext_uns = true; 766b2167459SRichard Henderson break; 767b2167459SRichard Henderson default: 768a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 769b2167459SRichard Henderson } 770b2167459SRichard Henderson 7714fe9533aSRichard Henderson if (cf & 1) { 7724fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 7734fe9533aSRichard Henderson } 7744fe9533aSRichard Henderson if (cond_need_ext(ctx, d)) { 775aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 776aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 7774fe9533aSRichard Henderson 7784fe9533aSRichard Henderson if (ext_uns) { 7796fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 7806fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 7814fe9533aSRichard Henderson } else { 7826fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 7836fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 7844fe9533aSRichard Henderson } 7854fe9533aSRichard Henderson return cond_make_tmp(tc, t1, t2); 7864fe9533aSRichard Henderson } 7874fe9533aSRichard Henderson return cond_make(tc, in1, in2); 788b2167459SRichard Henderson } 789b2167459SRichard Henderson 790df0232feSRichard Henderson /* 791df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 792df0232feSRichard Henderson * computed, and use of them is undefined. 793df0232feSRichard Henderson * 794df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 795df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 796df0232feSRichard Henderson * how cases c={2,3} are treated. 797df0232feSRichard Henderson */ 798b2167459SRichard Henderson 799b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 8006fd0c7bcSRichard Henderson TCGv_i64 res) 801b2167459SRichard Henderson { 802b5af8423SRichard Henderson TCGCond tc; 803b5af8423SRichard Henderson bool ext_uns; 804a751eb31SRichard Henderson 805df0232feSRichard Henderson switch (cf) { 806df0232feSRichard Henderson case 0: /* never */ 807df0232feSRichard Henderson case 9: /* undef, C */ 808df0232feSRichard Henderson case 11: /* undef, C & !Z */ 809df0232feSRichard Henderson case 12: /* undef, V */ 810df0232feSRichard Henderson return cond_make_f(); 811df0232feSRichard Henderson 812df0232feSRichard Henderson case 1: /* true */ 813df0232feSRichard Henderson case 8: /* undef, !C */ 814df0232feSRichard Henderson case 10: /* undef, !C | Z */ 815df0232feSRichard Henderson case 13: /* undef, !V */ 816df0232feSRichard Henderson return cond_make_t(); 817df0232feSRichard Henderson 818df0232feSRichard Henderson case 2: /* == */ 819b5af8423SRichard Henderson tc = TCG_COND_EQ; 820b5af8423SRichard Henderson ext_uns = true; 821b5af8423SRichard Henderson break; 822df0232feSRichard Henderson case 3: /* <> */ 823b5af8423SRichard Henderson tc = TCG_COND_NE; 824b5af8423SRichard Henderson ext_uns = true; 825b5af8423SRichard Henderson break; 826df0232feSRichard Henderson case 4: /* < */ 827b5af8423SRichard Henderson tc = TCG_COND_LT; 828b5af8423SRichard Henderson ext_uns = false; 829b5af8423SRichard Henderson break; 830df0232feSRichard Henderson case 5: /* >= */ 831b5af8423SRichard Henderson tc = TCG_COND_GE; 832b5af8423SRichard Henderson ext_uns = false; 833b5af8423SRichard Henderson break; 834df0232feSRichard Henderson case 6: /* <= */ 835b5af8423SRichard Henderson tc = TCG_COND_LE; 836b5af8423SRichard Henderson ext_uns = false; 837b5af8423SRichard Henderson break; 838df0232feSRichard Henderson case 7: /* > */ 839b5af8423SRichard Henderson tc = TCG_COND_GT; 840b5af8423SRichard Henderson ext_uns = false; 841b5af8423SRichard Henderson break; 842df0232feSRichard Henderson 843df0232feSRichard Henderson case 14: /* OD */ 844df0232feSRichard Henderson case 15: /* EV */ 845a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, NULL); 846df0232feSRichard Henderson 847df0232feSRichard Henderson default: 848df0232feSRichard Henderson g_assert_not_reached(); 849b2167459SRichard Henderson } 850b5af8423SRichard Henderson 851b5af8423SRichard Henderson if (cond_need_ext(ctx, d)) { 852aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 853b5af8423SRichard Henderson 854b5af8423SRichard Henderson if (ext_uns) { 8556fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 856b5af8423SRichard Henderson } else { 8576fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 858b5af8423SRichard Henderson } 859b5af8423SRichard Henderson return cond_make_0_tmp(tc, tmp); 860b5af8423SRichard Henderson } 861b5af8423SRichard Henderson return cond_make_0(tc, res); 862b2167459SRichard Henderson } 863b2167459SRichard Henderson 86498cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 86598cd9ca7SRichard Henderson 8664fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 8676fd0c7bcSRichard Henderson TCGv_i64 res) 86898cd9ca7SRichard Henderson { 86998cd9ca7SRichard Henderson unsigned c, f; 87098cd9ca7SRichard Henderson 87198cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 87298cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 87398cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 87498cd9ca7SRichard Henderson c = orig & 3; 87598cd9ca7SRichard Henderson if (c == 3) { 87698cd9ca7SRichard Henderson c = 7; 87798cd9ca7SRichard Henderson } 87898cd9ca7SRichard Henderson f = (orig & 4) / 4; 87998cd9ca7SRichard Henderson 880b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 88198cd9ca7SRichard Henderson } 88298cd9ca7SRichard Henderson 883b2167459SRichard Henderson /* Similar, but for unit conditions. */ 884b2167459SRichard Henderson 8856fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res, 8866fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 887b2167459SRichard Henderson { 888b2167459SRichard Henderson DisasCond cond; 8896fd0c7bcSRichard Henderson TCGv_i64 tmp, cb = NULL; 890c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 891b2167459SRichard Henderson 892b2167459SRichard Henderson if (cf & 8) { 893b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 894b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 895b2167459SRichard Henderson * leaves us with carry bits spread across two words. 896b2167459SRichard Henderson */ 897aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 898aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 8996fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, in1, in2); 9006fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, in1, in2); 9016fd0c7bcSRichard Henderson tcg_gen_andc_i64(cb, cb, res); 9026fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, cb, tmp); 903b2167459SRichard Henderson } 904b2167459SRichard Henderson 905b2167459SRichard Henderson switch (cf >> 1) { 906b2167459SRichard Henderson case 0: /* never / TR */ 907b2167459SRichard Henderson case 1: /* undefined */ 908b2167459SRichard Henderson case 5: /* undefined */ 909b2167459SRichard Henderson cond = cond_make_f(); 910b2167459SRichard Henderson break; 911b2167459SRichard Henderson 912b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 913b2167459SRichard Henderson /* See hasless(v,1) from 914b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 915b2167459SRichard Henderson */ 916aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9176fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u); 9186fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9196fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u); 920b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 921b2167459SRichard Henderson break; 922b2167459SRichard Henderson 923b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 924aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9256fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u); 9266fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9276fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u); 928b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 929b2167459SRichard Henderson break; 930b2167459SRichard Henderson 931b2167459SRichard Henderson case 4: /* SDC / NDC */ 9326fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u); 933b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 934b2167459SRichard Henderson break; 935b2167459SRichard Henderson 936b2167459SRichard Henderson case 6: /* SBC / NBC */ 9376fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u); 938b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 939b2167459SRichard Henderson break; 940b2167459SRichard Henderson 941b2167459SRichard Henderson case 7: /* SHC / NHC */ 9426fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u); 943b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 944b2167459SRichard Henderson break; 945b2167459SRichard Henderson 946b2167459SRichard Henderson default: 947b2167459SRichard Henderson g_assert_not_reached(); 948b2167459SRichard Henderson } 949b2167459SRichard Henderson if (cf & 1) { 950b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 951b2167459SRichard Henderson } 952b2167459SRichard Henderson 953b2167459SRichard Henderson return cond; 954b2167459SRichard Henderson } 955b2167459SRichard Henderson 9566fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 9576fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 95872ca8753SRichard Henderson { 95972ca8753SRichard Henderson if (cond_need_ext(ctx, d)) { 960aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 9616fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 96272ca8753SRichard Henderson return t; 96372ca8753SRichard Henderson } 96472ca8753SRichard Henderson return cb_msb; 96572ca8753SRichard Henderson } 96672ca8753SRichard Henderson 9676fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 96872ca8753SRichard Henderson { 96972ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 97072ca8753SRichard Henderson } 97172ca8753SRichard Henderson 972b2167459SRichard Henderson /* Compute signed overflow for addition. */ 9736fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 9746fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 975b2167459SRichard Henderson { 976aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 977aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 978b2167459SRichard Henderson 9796fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 9806fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 9816fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 982b2167459SRichard Henderson 983b2167459SRichard Henderson return sv; 984b2167459SRichard Henderson } 985b2167459SRichard Henderson 986b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 9876fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 9886fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 989b2167459SRichard Henderson { 990aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 991aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 992b2167459SRichard Henderson 9936fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 9946fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 9956fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 996b2167459SRichard Henderson 997b2167459SRichard Henderson return sv; 998b2167459SRichard Henderson } 999b2167459SRichard Henderson 10006fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 10016fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1002faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1003b2167459SRichard Henderson { 10046fd0c7bcSRichard Henderson TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp; 1005b2167459SRichard Henderson unsigned c = cf >> 1; 1006b2167459SRichard Henderson DisasCond cond; 1007b2167459SRichard Henderson 1008aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1009f764718dSRichard Henderson cb = NULL; 1010f764718dSRichard Henderson cb_msb = NULL; 1011bdcccc17SRichard Henderson cb_cond = NULL; 1012b2167459SRichard Henderson 1013b2167459SRichard Henderson if (shift) { 1014aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10156fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1016b2167459SRichard Henderson in1 = tmp; 1017b2167459SRichard Henderson } 1018b2167459SRichard Henderson 1019b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1020aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1021aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1022bdcccc17SRichard Henderson 1023a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1024b2167459SRichard Henderson if (is_c) { 10256fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1026a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1027b2167459SRichard Henderson } 10286fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 10296fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1030bdcccc17SRichard Henderson if (cond_need_cb(c)) { 1031bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 1032b2167459SRichard Henderson } 1033b2167459SRichard Henderson } else { 10346fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1035b2167459SRichard Henderson if (is_c) { 10366fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1037b2167459SRichard Henderson } 1038b2167459SRichard Henderson } 1039b2167459SRichard Henderson 1040b2167459SRichard Henderson /* Compute signed overflow if required. */ 1041f764718dSRichard Henderson sv = NULL; 1042b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1043b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 1044b2167459SRichard Henderson if (is_tsv) { 1045b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 1046ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1047b2167459SRichard Henderson } 1048b2167459SRichard Henderson } 1049b2167459SRichard Henderson 1050b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1051a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, cb_cond, sv); 1052b2167459SRichard Henderson if (is_tc) { 1053aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10546fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1055ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1056b2167459SRichard Henderson } 1057b2167459SRichard Henderson 1058b2167459SRichard Henderson /* Write back the result. */ 1059b2167459SRichard Henderson if (!is_l) { 1060b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1061b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1062b2167459SRichard Henderson } 1063b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1064b2167459SRichard Henderson 1065b2167459SRichard Henderson /* Install the new nullification. */ 1066b2167459SRichard Henderson cond_free(&ctx->null_cond); 1067b2167459SRichard Henderson ctx->null_cond = cond; 1068b2167459SRichard Henderson } 1069b2167459SRichard Henderson 1070faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 10710c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 10720c982a28SRichard Henderson { 10736fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 10740c982a28SRichard Henderson 10750c982a28SRichard Henderson if (a->cf) { 10760c982a28SRichard Henderson nullify_over(ctx); 10770c982a28SRichard Henderson } 10780c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 10790c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1080faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1081faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 10820c982a28SRichard Henderson return nullify_end(ctx); 10830c982a28SRichard Henderson } 10840c982a28SRichard Henderson 10850588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 10860588e061SRichard Henderson bool is_tsv, bool is_tc) 10870588e061SRichard Henderson { 10886fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 10890588e061SRichard Henderson 10900588e061SRichard Henderson if (a->cf) { 10910588e061SRichard Henderson nullify_over(ctx); 10920588e061SRichard Henderson } 10936fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 10940588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1095faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1096faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 10970588e061SRichard Henderson return nullify_end(ctx); 10980588e061SRichard Henderson } 10990588e061SRichard Henderson 11006fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 11016fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 110263c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1103b2167459SRichard Henderson { 1104a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1105b2167459SRichard Henderson unsigned c = cf >> 1; 1106b2167459SRichard Henderson DisasCond cond; 1107b2167459SRichard Henderson 1108aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1109aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1110aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1111b2167459SRichard Henderson 1112b2167459SRichard Henderson if (is_b) { 1113b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 11146fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1115a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1116a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1117a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 11186fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 11196fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1120b2167459SRichard Henderson } else { 1121bdcccc17SRichard Henderson /* 1122bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1123bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1124bdcccc17SRichard Henderson */ 11256fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1126a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 11276fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 11286fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1129b2167459SRichard Henderson } 1130b2167459SRichard Henderson 1131b2167459SRichard Henderson /* Compute signed overflow if required. */ 1132f764718dSRichard Henderson sv = NULL; 1133b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1134b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1135b2167459SRichard Henderson if (is_tsv) { 1136ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1137b2167459SRichard Henderson } 1138b2167459SRichard Henderson } 1139b2167459SRichard Henderson 1140b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1141b2167459SRichard Henderson if (!is_b) { 11424fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1143b2167459SRichard Henderson } else { 1144a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1145b2167459SRichard Henderson } 1146b2167459SRichard Henderson 1147b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1148b2167459SRichard Henderson if (is_tc) { 1149aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11506fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1151ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1152b2167459SRichard Henderson } 1153b2167459SRichard Henderson 1154b2167459SRichard Henderson /* Write back the result. */ 1155b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1156b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1157b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1158b2167459SRichard Henderson 1159b2167459SRichard Henderson /* Install the new nullification. */ 1160b2167459SRichard Henderson cond_free(&ctx->null_cond); 1161b2167459SRichard Henderson ctx->null_cond = cond; 1162b2167459SRichard Henderson } 1163b2167459SRichard Henderson 116463c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 11650c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 11660c982a28SRichard Henderson { 11676fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 11680c982a28SRichard Henderson 11690c982a28SRichard Henderson if (a->cf) { 11700c982a28SRichard Henderson nullify_over(ctx); 11710c982a28SRichard Henderson } 11720c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 11730c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 117463c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 11750c982a28SRichard Henderson return nullify_end(ctx); 11760c982a28SRichard Henderson } 11770c982a28SRichard Henderson 11780588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 11790588e061SRichard Henderson { 11806fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11810588e061SRichard Henderson 11820588e061SRichard Henderson if (a->cf) { 11830588e061SRichard Henderson nullify_over(ctx); 11840588e061SRichard Henderson } 11856fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11860588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 118763c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 118863c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 11890588e061SRichard Henderson return nullify_end(ctx); 11900588e061SRichard Henderson } 11910588e061SRichard Henderson 11926fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 11936fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1194b2167459SRichard Henderson { 11956fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1196b2167459SRichard Henderson DisasCond cond; 1197b2167459SRichard Henderson 1198aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 11996fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1200b2167459SRichard Henderson 1201b2167459SRichard Henderson /* Compute signed overflow if required. */ 1202f764718dSRichard Henderson sv = NULL; 1203b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1204b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1205b2167459SRichard Henderson } 1206b2167459SRichard Henderson 1207b2167459SRichard Henderson /* Form the condition for the compare. */ 12084fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1209b2167459SRichard Henderson 1210b2167459SRichard Henderson /* Clear. */ 12116fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1212b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1213b2167459SRichard Henderson 1214b2167459SRichard Henderson /* Install the new nullification. */ 1215b2167459SRichard Henderson cond_free(&ctx->null_cond); 1216b2167459SRichard Henderson ctx->null_cond = cond; 1217b2167459SRichard Henderson } 1218b2167459SRichard Henderson 12196fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12206fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 12216fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1222b2167459SRichard Henderson { 12236fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1224b2167459SRichard Henderson 1225b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1226b2167459SRichard Henderson fn(dest, in1, in2); 1227b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1228b2167459SRichard Henderson 1229b2167459SRichard Henderson /* Install the new nullification. */ 1230b2167459SRichard Henderson cond_free(&ctx->null_cond); 1231b2167459SRichard Henderson if (cf) { 1232b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1233b2167459SRichard Henderson } 1234b2167459SRichard Henderson } 1235b2167459SRichard Henderson 1236fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12376fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 12380c982a28SRichard Henderson { 12396fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12400c982a28SRichard Henderson 12410c982a28SRichard Henderson if (a->cf) { 12420c982a28SRichard Henderson nullify_over(ctx); 12430c982a28SRichard Henderson } 12440c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12450c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1246fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 12470c982a28SRichard Henderson return nullify_end(ctx); 12480c982a28SRichard Henderson } 12490c982a28SRichard Henderson 12506fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12516fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, bool is_tc, 12526fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1253b2167459SRichard Henderson { 12546fd0c7bcSRichard Henderson TCGv_i64 dest; 1255b2167459SRichard Henderson DisasCond cond; 1256b2167459SRichard Henderson 1257b2167459SRichard Henderson if (cf == 0) { 1258b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 1259b2167459SRichard Henderson fn(dest, in1, in2); 1260b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1261b2167459SRichard Henderson cond_free(&ctx->null_cond); 1262b2167459SRichard Henderson } else { 1263aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1264b2167459SRichard Henderson fn(dest, in1, in2); 1265b2167459SRichard Henderson 126659963d8fSRichard Henderson cond = do_unit_cond(cf, d, dest, in1, in2); 1267b2167459SRichard Henderson 1268b2167459SRichard Henderson if (is_tc) { 1269aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 12706fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1271ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1272b2167459SRichard Henderson } 1273b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1274b2167459SRichard Henderson 1275b2167459SRichard Henderson cond_free(&ctx->null_cond); 1276b2167459SRichard Henderson ctx->null_cond = cond; 1277b2167459SRichard Henderson } 1278b2167459SRichard Henderson } 1279b2167459SRichard Henderson 128086f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 12818d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 12828d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 12838d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 12848d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 12856fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 128686f8d05fSRichard Henderson { 128786f8d05fSRichard Henderson TCGv_ptr ptr; 12886fd0c7bcSRichard Henderson TCGv_i64 tmp; 128986f8d05fSRichard Henderson TCGv_i64 spc; 129086f8d05fSRichard Henderson 129186f8d05fSRichard Henderson if (sp != 0) { 12928d6ae7fbSRichard Henderson if (sp < 0) { 12938d6ae7fbSRichard Henderson sp = ~sp; 12948d6ae7fbSRichard Henderson } 12956fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 12968d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 12978d6ae7fbSRichard Henderson return spc; 129886f8d05fSRichard Henderson } 1299494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1300494737b7SRichard Henderson return cpu_srH; 1301494737b7SRichard Henderson } 130286f8d05fSRichard Henderson 130386f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1304aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 13056fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 130686f8d05fSRichard Henderson 1307698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 13086fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 13096fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 13106fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 131186f8d05fSRichard Henderson 1312ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 131386f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 131486f8d05fSRichard Henderson 131586f8d05fSRichard Henderson return spc; 131686f8d05fSRichard Henderson } 131786f8d05fSRichard Henderson #endif 131886f8d05fSRichard Henderson 13196fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1320c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 132186f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 132286f8d05fSRichard Henderson { 13236fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 13246fd0c7bcSRichard Henderson TCGv_i64 ofs; 13256fd0c7bcSRichard Henderson TCGv_i64 addr; 132686f8d05fSRichard Henderson 132786f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 132886f8d05fSRichard Henderson if (rx) { 1329aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13306fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 13316fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 133286f8d05fSRichard Henderson } else if (disp || modify) { 1333aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13346fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 133586f8d05fSRichard Henderson } else { 133686f8d05fSRichard Henderson ofs = base; 133786f8d05fSRichard Henderson } 133886f8d05fSRichard Henderson 133986f8d05fSRichard Henderson *pofs = ofs; 13406fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 1341d265360fSRichard Henderson tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx)); 1342698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 134386f8d05fSRichard Henderson if (!is_phys) { 1344d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 134586f8d05fSRichard Henderson } 134686f8d05fSRichard Henderson #endif 134786f8d05fSRichard Henderson } 134886f8d05fSRichard Henderson 134996d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 135096d6407fSRichard Henderson * < 0 for pre-modify, 135196d6407fSRichard Henderson * > 0 for post-modify, 135296d6407fSRichard Henderson * = 0 for no base register update. 135396d6407fSRichard Henderson */ 135496d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1355c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 135614776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 135796d6407fSRichard Henderson { 13586fd0c7bcSRichard Henderson TCGv_i64 ofs; 13596fd0c7bcSRichard Henderson TCGv_i64 addr; 136096d6407fSRichard Henderson 136196d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 136296d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 136396d6407fSRichard Henderson 136486f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 136586f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1366c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 136786f8d05fSRichard Henderson if (modify) { 136886f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 136996d6407fSRichard Henderson } 137096d6407fSRichard Henderson } 137196d6407fSRichard Henderson 137296d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1373c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 137414776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 137596d6407fSRichard Henderson { 13766fd0c7bcSRichard Henderson TCGv_i64 ofs; 13776fd0c7bcSRichard Henderson TCGv_i64 addr; 137896d6407fSRichard Henderson 137996d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 138096d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 138196d6407fSRichard Henderson 138286f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 138386f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1384217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 138586f8d05fSRichard Henderson if (modify) { 138686f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 138796d6407fSRichard Henderson } 138896d6407fSRichard Henderson } 138996d6407fSRichard Henderson 139096d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1391c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 139214776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 139396d6407fSRichard Henderson { 13946fd0c7bcSRichard Henderson TCGv_i64 ofs; 13956fd0c7bcSRichard Henderson TCGv_i64 addr; 139696d6407fSRichard Henderson 139796d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 139896d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 139996d6407fSRichard Henderson 140086f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 140186f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1402217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 140386f8d05fSRichard Henderson if (modify) { 140486f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 140596d6407fSRichard Henderson } 140696d6407fSRichard Henderson } 140796d6407fSRichard Henderson 140896d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1409c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 141014776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 141196d6407fSRichard Henderson { 14126fd0c7bcSRichard Henderson TCGv_i64 ofs; 14136fd0c7bcSRichard Henderson TCGv_i64 addr; 141496d6407fSRichard Henderson 141596d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 141696d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 141796d6407fSRichard Henderson 141886f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 141986f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1420217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 142186f8d05fSRichard Henderson if (modify) { 142286f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 142396d6407fSRichard Henderson } 142496d6407fSRichard Henderson } 142596d6407fSRichard Henderson 14261cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1427c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 142814776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 142996d6407fSRichard Henderson { 14306fd0c7bcSRichard Henderson TCGv_i64 dest; 143196d6407fSRichard Henderson 143296d6407fSRichard Henderson nullify_over(ctx); 143396d6407fSRichard Henderson 143496d6407fSRichard Henderson if (modify == 0) { 143596d6407fSRichard Henderson /* No base register update. */ 143696d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 143796d6407fSRichard Henderson } else { 143896d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1439aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 144096d6407fSRichard Henderson } 14416fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 144296d6407fSRichard Henderson save_gpr(ctx, rt, dest); 144396d6407fSRichard Henderson 14441cd012a5SRichard Henderson return nullify_end(ctx); 144596d6407fSRichard Henderson } 144696d6407fSRichard Henderson 1447740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1448c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 144986f8d05fSRichard Henderson unsigned sp, int modify) 145096d6407fSRichard Henderson { 145196d6407fSRichard Henderson TCGv_i32 tmp; 145296d6407fSRichard Henderson 145396d6407fSRichard Henderson nullify_over(ctx); 145496d6407fSRichard Henderson 145596d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 145686f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 145796d6407fSRichard Henderson save_frw_i32(rt, tmp); 145896d6407fSRichard Henderson 145996d6407fSRichard Henderson if (rt == 0) { 1460ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 146196d6407fSRichard Henderson } 146296d6407fSRichard Henderson 1463740038d7SRichard Henderson return nullify_end(ctx); 146496d6407fSRichard Henderson } 146596d6407fSRichard Henderson 1466740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1467740038d7SRichard Henderson { 1468740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1469740038d7SRichard Henderson a->disp, a->sp, a->m); 1470740038d7SRichard Henderson } 1471740038d7SRichard Henderson 1472740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1473c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 147486f8d05fSRichard Henderson unsigned sp, int modify) 147596d6407fSRichard Henderson { 147696d6407fSRichard Henderson TCGv_i64 tmp; 147796d6407fSRichard Henderson 147896d6407fSRichard Henderson nullify_over(ctx); 147996d6407fSRichard Henderson 148096d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1481fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 148296d6407fSRichard Henderson save_frd(rt, tmp); 148396d6407fSRichard Henderson 148496d6407fSRichard Henderson if (rt == 0) { 1485ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 148696d6407fSRichard Henderson } 148796d6407fSRichard Henderson 1488740038d7SRichard Henderson return nullify_end(ctx); 1489740038d7SRichard Henderson } 1490740038d7SRichard Henderson 1491740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1492740038d7SRichard Henderson { 1493740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1494740038d7SRichard Henderson a->disp, a->sp, a->m); 149596d6407fSRichard Henderson } 149696d6407fSRichard Henderson 14971cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1498c53e401eSRichard Henderson int64_t disp, unsigned sp, 149914776ab5STony Nguyen int modify, MemOp mop) 150096d6407fSRichard Henderson { 150196d6407fSRichard Henderson nullify_over(ctx); 15026fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 15031cd012a5SRichard Henderson return nullify_end(ctx); 150496d6407fSRichard Henderson } 150596d6407fSRichard Henderson 1506740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1507c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 150886f8d05fSRichard Henderson unsigned sp, int modify) 150996d6407fSRichard Henderson { 151096d6407fSRichard Henderson TCGv_i32 tmp; 151196d6407fSRichard Henderson 151296d6407fSRichard Henderson nullify_over(ctx); 151396d6407fSRichard Henderson 151496d6407fSRichard Henderson tmp = load_frw_i32(rt); 151586f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 151696d6407fSRichard Henderson 1517740038d7SRichard Henderson return nullify_end(ctx); 151896d6407fSRichard Henderson } 151996d6407fSRichard Henderson 1520740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1521740038d7SRichard Henderson { 1522740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1523740038d7SRichard Henderson a->disp, a->sp, a->m); 1524740038d7SRichard Henderson } 1525740038d7SRichard Henderson 1526740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1527c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 152886f8d05fSRichard Henderson unsigned sp, int modify) 152996d6407fSRichard Henderson { 153096d6407fSRichard Henderson TCGv_i64 tmp; 153196d6407fSRichard Henderson 153296d6407fSRichard Henderson nullify_over(ctx); 153396d6407fSRichard Henderson 153496d6407fSRichard Henderson tmp = load_frd(rt); 1535fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 153696d6407fSRichard Henderson 1537740038d7SRichard Henderson return nullify_end(ctx); 1538740038d7SRichard Henderson } 1539740038d7SRichard Henderson 1540740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1541740038d7SRichard Henderson { 1542740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1543740038d7SRichard Henderson a->disp, a->sp, a->m); 154496d6407fSRichard Henderson } 154596d6407fSRichard Henderson 15461ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1547ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1548ebe9383cSRichard Henderson { 1549ebe9383cSRichard Henderson TCGv_i32 tmp; 1550ebe9383cSRichard Henderson 1551ebe9383cSRichard Henderson nullify_over(ctx); 1552ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1553ebe9383cSRichard Henderson 1554ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1555ebe9383cSRichard Henderson 1556ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 15571ca74648SRichard Henderson return nullify_end(ctx); 1558ebe9383cSRichard Henderson } 1559ebe9383cSRichard Henderson 15601ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1561ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1562ebe9383cSRichard Henderson { 1563ebe9383cSRichard Henderson TCGv_i32 dst; 1564ebe9383cSRichard Henderson TCGv_i64 src; 1565ebe9383cSRichard Henderson 1566ebe9383cSRichard Henderson nullify_over(ctx); 1567ebe9383cSRichard Henderson src = load_frd(ra); 1568ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1569ebe9383cSRichard Henderson 1570ad75a51eSRichard Henderson func(dst, tcg_env, src); 1571ebe9383cSRichard Henderson 1572ebe9383cSRichard Henderson save_frw_i32(rt, dst); 15731ca74648SRichard Henderson return nullify_end(ctx); 1574ebe9383cSRichard Henderson } 1575ebe9383cSRichard Henderson 15761ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1577ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1578ebe9383cSRichard Henderson { 1579ebe9383cSRichard Henderson TCGv_i64 tmp; 1580ebe9383cSRichard Henderson 1581ebe9383cSRichard Henderson nullify_over(ctx); 1582ebe9383cSRichard Henderson tmp = load_frd0(ra); 1583ebe9383cSRichard Henderson 1584ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1585ebe9383cSRichard Henderson 1586ebe9383cSRichard Henderson save_frd(rt, tmp); 15871ca74648SRichard Henderson return nullify_end(ctx); 1588ebe9383cSRichard Henderson } 1589ebe9383cSRichard Henderson 15901ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1591ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1592ebe9383cSRichard Henderson { 1593ebe9383cSRichard Henderson TCGv_i32 src; 1594ebe9383cSRichard Henderson TCGv_i64 dst; 1595ebe9383cSRichard Henderson 1596ebe9383cSRichard Henderson nullify_over(ctx); 1597ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1598ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1599ebe9383cSRichard Henderson 1600ad75a51eSRichard Henderson func(dst, tcg_env, src); 1601ebe9383cSRichard Henderson 1602ebe9383cSRichard Henderson save_frd(rt, dst); 16031ca74648SRichard Henderson return nullify_end(ctx); 1604ebe9383cSRichard Henderson } 1605ebe9383cSRichard Henderson 16061ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1607ebe9383cSRichard Henderson unsigned ra, unsigned rb, 160831234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1609ebe9383cSRichard Henderson { 1610ebe9383cSRichard Henderson TCGv_i32 a, b; 1611ebe9383cSRichard Henderson 1612ebe9383cSRichard Henderson nullify_over(ctx); 1613ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1614ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1615ebe9383cSRichard Henderson 1616ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1617ebe9383cSRichard Henderson 1618ebe9383cSRichard Henderson save_frw_i32(rt, a); 16191ca74648SRichard Henderson return nullify_end(ctx); 1620ebe9383cSRichard Henderson } 1621ebe9383cSRichard Henderson 16221ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1623ebe9383cSRichard Henderson unsigned ra, unsigned rb, 162431234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1625ebe9383cSRichard Henderson { 1626ebe9383cSRichard Henderson TCGv_i64 a, b; 1627ebe9383cSRichard Henderson 1628ebe9383cSRichard Henderson nullify_over(ctx); 1629ebe9383cSRichard Henderson a = load_frd0(ra); 1630ebe9383cSRichard Henderson b = load_frd0(rb); 1631ebe9383cSRichard Henderson 1632ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1633ebe9383cSRichard Henderson 1634ebe9383cSRichard Henderson save_frd(rt, a); 16351ca74648SRichard Henderson return nullify_end(ctx); 1636ebe9383cSRichard Henderson } 1637ebe9383cSRichard Henderson 163898cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 163998cd9ca7SRichard Henderson have already had nullification handled. */ 1640c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest, 164198cd9ca7SRichard Henderson unsigned link, bool is_n) 164298cd9ca7SRichard Henderson { 164398cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 164498cd9ca7SRichard Henderson if (link != 0) { 1645741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 164698cd9ca7SRichard Henderson } 164798cd9ca7SRichard Henderson ctx->iaoq_n = dest; 164898cd9ca7SRichard Henderson if (is_n) { 164998cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 165098cd9ca7SRichard Henderson } 165198cd9ca7SRichard Henderson } else { 165298cd9ca7SRichard Henderson nullify_over(ctx); 165398cd9ca7SRichard Henderson 165498cd9ca7SRichard Henderson if (link != 0) { 1655741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 165698cd9ca7SRichard Henderson } 165798cd9ca7SRichard Henderson 165898cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 165998cd9ca7SRichard Henderson nullify_set(ctx, 0); 166098cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 166198cd9ca7SRichard Henderson } else { 166298cd9ca7SRichard Henderson nullify_set(ctx, is_n); 166398cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 166498cd9ca7SRichard Henderson } 166598cd9ca7SRichard Henderson 166631234768SRichard Henderson nullify_end(ctx); 166798cd9ca7SRichard Henderson 166898cd9ca7SRichard Henderson nullify_set(ctx, 0); 166998cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 167031234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 167198cd9ca7SRichard Henderson } 167201afb7beSRichard Henderson return true; 167398cd9ca7SRichard Henderson } 167498cd9ca7SRichard Henderson 167598cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 167698cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1677c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 167898cd9ca7SRichard Henderson DisasCond *cond) 167998cd9ca7SRichard Henderson { 1680c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, disp); 168198cd9ca7SRichard Henderson TCGLabel *taken = NULL; 168298cd9ca7SRichard Henderson TCGCond c = cond->c; 168398cd9ca7SRichard Henderson bool n; 168498cd9ca7SRichard Henderson 168598cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 168698cd9ca7SRichard Henderson 168798cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 168898cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 168901afb7beSRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 169098cd9ca7SRichard Henderson } 169198cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 169201afb7beSRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 169398cd9ca7SRichard Henderson } 169498cd9ca7SRichard Henderson 169598cd9ca7SRichard Henderson taken = gen_new_label(); 16966fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 169798cd9ca7SRichard Henderson cond_free(cond); 169898cd9ca7SRichard Henderson 169998cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 170098cd9ca7SRichard Henderson n = is_n && disp < 0; 170198cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 170298cd9ca7SRichard Henderson nullify_set(ctx, 0); 1703a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 170498cd9ca7SRichard Henderson } else { 170598cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 170698cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 170798cd9ca7SRichard Henderson ctx->null_lab = NULL; 170898cd9ca7SRichard Henderson } 170998cd9ca7SRichard Henderson nullify_set(ctx, n); 1710c301f34eSRichard Henderson if (ctx->iaoq_n == -1) { 1711c301f34eSRichard Henderson /* The temporary iaoq_n_var died at the branch above. 1712c301f34eSRichard Henderson Regenerate it here instead of saving it. */ 17136fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 1714c301f34eSRichard Henderson } 1715a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 171698cd9ca7SRichard Henderson } 171798cd9ca7SRichard Henderson 171898cd9ca7SRichard Henderson gen_set_label(taken); 171998cd9ca7SRichard Henderson 172098cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 172198cd9ca7SRichard Henderson n = is_n && disp >= 0; 172298cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 172398cd9ca7SRichard Henderson nullify_set(ctx, 0); 1724a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, dest, dest + 4); 172598cd9ca7SRichard Henderson } else { 172698cd9ca7SRichard Henderson nullify_set(ctx, n); 1727a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 172898cd9ca7SRichard Henderson } 172998cd9ca7SRichard Henderson 173098cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 173198cd9ca7SRichard Henderson if (ctx->null_lab) { 173298cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 173398cd9ca7SRichard Henderson ctx->null_lab = NULL; 173431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 173598cd9ca7SRichard Henderson } else { 173631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 173798cd9ca7SRichard Henderson } 173801afb7beSRichard Henderson return true; 173998cd9ca7SRichard Henderson } 174098cd9ca7SRichard Henderson 174198cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 174298cd9ca7SRichard Henderson nullification of the branch itself. */ 17436fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest, 174498cd9ca7SRichard Henderson unsigned link, bool is_n) 174598cd9ca7SRichard Henderson { 17466fd0c7bcSRichard Henderson TCGv_i64 a0, a1, next, tmp; 174798cd9ca7SRichard Henderson TCGCond c; 174898cd9ca7SRichard Henderson 174998cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 175098cd9ca7SRichard Henderson 175198cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 175298cd9ca7SRichard Henderson if (link != 0) { 1753741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 175498cd9ca7SRichard Henderson } 1755aac0f603SRichard Henderson next = tcg_temp_new_i64(); 17566fd0c7bcSRichard Henderson tcg_gen_mov_i64(next, dest); 175798cd9ca7SRichard Henderson if (is_n) { 1758c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1759a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next); 17606fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, next, 4); 1761a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 1762c301f34eSRichard Henderson nullify_set(ctx, 0); 176331234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 176401afb7beSRichard Henderson return true; 1765c301f34eSRichard Henderson } 176698cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 176798cd9ca7SRichard Henderson } 1768c301f34eSRichard Henderson ctx->iaoq_n = -1; 1769c301f34eSRichard Henderson ctx->iaoq_n_var = next; 177098cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 177198cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 177298cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 17734137cb83SRichard Henderson tracepoint in effect). Since the goto_ptr that we must use 177498cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 177598cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 177698cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 177798cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 177898cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 177998cd9ca7SRichard Henderson 178098cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 178198cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 178298cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 1783a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest); 1784aac0f603SRichard Henderson next = tcg_temp_new_i64(); 17856fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, dest, 4); 1786a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 178798cd9ca7SRichard Henderson 178898cd9ca7SRichard Henderson nullify_over(ctx); 178998cd9ca7SRichard Henderson if (link != 0) { 17909a91dd84SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 179198cd9ca7SRichard Henderson } 17927f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 179301afb7beSRichard Henderson return nullify_end(ctx); 179498cd9ca7SRichard Henderson } else { 179598cd9ca7SRichard Henderson c = ctx->null_cond.c; 179698cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 179798cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 179898cd9ca7SRichard Henderson 1799aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 1800aac0f603SRichard Henderson next = tcg_temp_new_i64(); 180198cd9ca7SRichard Henderson 1802741322f4SRichard Henderson copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var); 18036fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest); 180498cd9ca7SRichard Henderson ctx->iaoq_n = -1; 180598cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 180698cd9ca7SRichard Henderson 180798cd9ca7SRichard Henderson if (link != 0) { 18086fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 180998cd9ca7SRichard Henderson } 181098cd9ca7SRichard Henderson 181198cd9ca7SRichard Henderson if (is_n) { 181298cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 181398cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 181498cd9ca7SRichard Henderson to the branch. */ 18156fd0c7bcSRichard Henderson tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1); 181698cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 181798cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 181898cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 181998cd9ca7SRichard Henderson } else { 182098cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 182198cd9ca7SRichard Henderson } 182298cd9ca7SRichard Henderson } 182301afb7beSRichard Henderson return true; 182498cd9ca7SRichard Henderson } 182598cd9ca7SRichard Henderson 1826660eefe1SRichard Henderson /* Implement 1827660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1828660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1829660eefe1SRichard Henderson * else 1830660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1831660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1832660eefe1SRichard Henderson */ 18336fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1834660eefe1SRichard Henderson { 18356fd0c7bcSRichard Henderson TCGv_i64 dest; 1836660eefe1SRichard Henderson switch (ctx->privilege) { 1837660eefe1SRichard Henderson case 0: 1838660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 1839660eefe1SRichard Henderson return offset; 1840660eefe1SRichard Henderson case 3: 1841993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 1842aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18436fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1844660eefe1SRichard Henderson break; 1845660eefe1SRichard Henderson default: 1846aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18476fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 18486fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 18496fd0c7bcSRichard Henderson tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset); 1850660eefe1SRichard Henderson break; 1851660eefe1SRichard Henderson } 1852660eefe1SRichard Henderson return dest; 1853660eefe1SRichard Henderson } 1854660eefe1SRichard Henderson 1855ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 18567ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 18577ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 18587ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 18597ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 18607ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 18617ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 18627ad439dfSRichard Henderson aforementioned BE. */ 186331234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 18647ad439dfSRichard Henderson { 18656fd0c7bcSRichard Henderson TCGv_i64 tmp; 1866a0180973SRichard Henderson 18677ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 18687ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 18698b81968cSMichael Tokarev next insn within the privileged page. */ 18707ad439dfSRichard Henderson switch (ctx->null_cond.c) { 18717ad439dfSRichard Henderson case TCG_COND_NEVER: 18727ad439dfSRichard Henderson break; 18737ad439dfSRichard Henderson case TCG_COND_ALWAYS: 18746fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 18757ad439dfSRichard Henderson goto do_sigill; 18767ad439dfSRichard Henderson default: 18777ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 18787ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 18797ad439dfSRichard Henderson g_assert_not_reached(); 18807ad439dfSRichard Henderson } 18817ad439dfSRichard Henderson 18827ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 18837ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 18847ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 18857ad439dfSRichard Henderson under such conditions. */ 18867ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 18877ad439dfSRichard Henderson goto do_sigill; 18887ad439dfSRichard Henderson } 18897ad439dfSRichard Henderson 1890ebd0e151SRichard Henderson switch (ctx->iaoq_f & -4) { 18917ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 18922986721dSRichard Henderson gen_excp_1(EXCP_IMP); 189331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 189431234768SRichard Henderson break; 18957ad439dfSRichard Henderson 18967ad439dfSRichard Henderson case 0xb0: /* LWS */ 18977ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 189831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 189931234768SRichard Henderson break; 19007ad439dfSRichard Henderson 19017ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 19026fd0c7bcSRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27])); 1903aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 19046fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_gr[31], 3); 1905a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 19066fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 1907a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 190831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 190931234768SRichard Henderson break; 19107ad439dfSRichard Henderson 19117ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 19127ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 191331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 191431234768SRichard Henderson break; 19157ad439dfSRichard Henderson 19167ad439dfSRichard Henderson default: 19177ad439dfSRichard Henderson do_sigill: 19182986721dSRichard Henderson gen_excp_1(EXCP_ILL); 191931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 192031234768SRichard Henderson break; 19217ad439dfSRichard Henderson } 19227ad439dfSRichard Henderson } 1923ba1d0b44SRichard Henderson #endif 19247ad439dfSRichard Henderson 1925deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 1926b2167459SRichard Henderson { 1927b2167459SRichard Henderson cond_free(&ctx->null_cond); 192831234768SRichard Henderson return true; 1929b2167459SRichard Henderson } 1930b2167459SRichard Henderson 193140f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 193298a9cb79SRichard Henderson { 193331234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 193498a9cb79SRichard Henderson } 193598a9cb79SRichard Henderson 1936e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 193798a9cb79SRichard Henderson { 193898a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 193998a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 194098a9cb79SRichard Henderson 194198a9cb79SRichard Henderson cond_free(&ctx->null_cond); 194231234768SRichard Henderson return true; 194398a9cb79SRichard Henderson } 194498a9cb79SRichard Henderson 1945c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 194698a9cb79SRichard Henderson { 1947c603e14aSRichard Henderson unsigned rt = a->t; 19486fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, rt); 19496fd0c7bcSRichard Henderson tcg_gen_movi_i64(tmp, ctx->iaoq_f); 195098a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 195198a9cb79SRichard Henderson 195298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 195331234768SRichard Henderson return true; 195498a9cb79SRichard Henderson } 195598a9cb79SRichard Henderson 1956c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 195798a9cb79SRichard Henderson { 1958c603e14aSRichard Henderson unsigned rt = a->t; 1959c603e14aSRichard Henderson unsigned rs = a->sp; 196033423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 196198a9cb79SRichard Henderson 196233423472SRichard Henderson load_spr(ctx, t0, rs); 196333423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 196433423472SRichard Henderson 1965967662cdSRichard Henderson save_gpr(ctx, rt, t0); 196698a9cb79SRichard Henderson 196798a9cb79SRichard Henderson cond_free(&ctx->null_cond); 196831234768SRichard Henderson return true; 196998a9cb79SRichard Henderson } 197098a9cb79SRichard Henderson 1971c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 197298a9cb79SRichard Henderson { 1973c603e14aSRichard Henderson unsigned rt = a->t; 1974c603e14aSRichard Henderson unsigned ctl = a->r; 19756fd0c7bcSRichard Henderson TCGv_i64 tmp; 197698a9cb79SRichard Henderson 197798a9cb79SRichard Henderson switch (ctl) { 197835136a77SRichard Henderson case CR_SAR: 1979c603e14aSRichard Henderson if (a->e == 0) { 198098a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 198198a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 19826fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 198398a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 198435136a77SRichard Henderson goto done; 198598a9cb79SRichard Henderson } 198698a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 198735136a77SRichard Henderson goto done; 198835136a77SRichard Henderson case CR_IT: /* Interval Timer */ 198935136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 199035136a77SRichard Henderson nullify_over(ctx); 199198a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 1992dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 199349c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 199431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 199549c29d6cSRichard Henderson } else { 199649c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 199749c29d6cSRichard Henderson } 199898a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 199931234768SRichard Henderson return nullify_end(ctx); 200098a9cb79SRichard Henderson case 26: 200198a9cb79SRichard Henderson case 27: 200298a9cb79SRichard Henderson break; 200398a9cb79SRichard Henderson default: 200498a9cb79SRichard Henderson /* All other control registers are privileged. */ 200535136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 200635136a77SRichard Henderson break; 200798a9cb79SRichard Henderson } 200898a9cb79SRichard Henderson 2009aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20106fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 201135136a77SRichard Henderson save_gpr(ctx, rt, tmp); 201235136a77SRichard Henderson 201335136a77SRichard Henderson done: 201498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 201531234768SRichard Henderson return true; 201698a9cb79SRichard Henderson } 201798a9cb79SRichard Henderson 2018c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 201933423472SRichard Henderson { 2020c603e14aSRichard Henderson unsigned rr = a->r; 2021c603e14aSRichard Henderson unsigned rs = a->sp; 2022967662cdSRichard Henderson TCGv_i64 tmp; 202333423472SRichard Henderson 202433423472SRichard Henderson if (rs >= 5) { 202533423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 202633423472SRichard Henderson } 202733423472SRichard Henderson nullify_over(ctx); 202833423472SRichard Henderson 2029967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2030967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 203133423472SRichard Henderson 203233423472SRichard Henderson if (rs >= 4) { 2033967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2034494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 203533423472SRichard Henderson } else { 2036967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 203733423472SRichard Henderson } 203833423472SRichard Henderson 203931234768SRichard Henderson return nullify_end(ctx); 204033423472SRichard Henderson } 204133423472SRichard Henderson 2042c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 204398a9cb79SRichard Henderson { 2044c603e14aSRichard Henderson unsigned ctl = a->t; 20456fd0c7bcSRichard Henderson TCGv_i64 reg; 20466fd0c7bcSRichard Henderson TCGv_i64 tmp; 204798a9cb79SRichard Henderson 204835136a77SRichard Henderson if (ctl == CR_SAR) { 20494845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2050aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20516fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 205298a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 205398a9cb79SRichard Henderson 205498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 205531234768SRichard Henderson return true; 205698a9cb79SRichard Henderson } 205798a9cb79SRichard Henderson 205835136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 205935136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 206035136a77SRichard Henderson 2061c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 206235136a77SRichard Henderson nullify_over(ctx); 20634845f015SSven Schnelle reg = load_gpr(ctx, a->r); 20644845f015SSven Schnelle 206535136a77SRichard Henderson switch (ctl) { 206635136a77SRichard Henderson case CR_IT: 2067ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 206835136a77SRichard Henderson break; 20694f5f2548SRichard Henderson case CR_EIRR: 2070ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 20714f5f2548SRichard Henderson break; 20724f5f2548SRichard Henderson case CR_EIEM: 2073ad75a51eSRichard Henderson gen_helper_write_eiem(tcg_env, reg); 207431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 20754f5f2548SRichard Henderson break; 20764f5f2548SRichard Henderson 207735136a77SRichard Henderson case CR_IIASQ: 207835136a77SRichard Henderson case CR_IIAOQ: 207935136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 208035136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2081aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20826fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 208335136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 20846fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 20856fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 208635136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 208735136a77SRichard Henderson break; 208835136a77SRichard Henderson 2089d5de20bdSSven Schnelle case CR_PID1: 2090d5de20bdSSven Schnelle case CR_PID2: 2091d5de20bdSSven Schnelle case CR_PID3: 2092d5de20bdSSven Schnelle case CR_PID4: 20936fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2094d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2095ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2096d5de20bdSSven Schnelle #endif 2097d5de20bdSSven Schnelle break; 2098d5de20bdSSven Schnelle 209935136a77SRichard Henderson default: 21006fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 210135136a77SRichard Henderson break; 210235136a77SRichard Henderson } 210331234768SRichard Henderson return nullify_end(ctx); 21044f5f2548SRichard Henderson #endif 210535136a77SRichard Henderson } 210635136a77SRichard Henderson 2107c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 210898a9cb79SRichard Henderson { 2109aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 211098a9cb79SRichard Henderson 21116fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 21126fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 211398a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 211498a9cb79SRichard Henderson 211598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 211631234768SRichard Henderson return true; 211798a9cb79SRichard Henderson } 211898a9cb79SRichard Henderson 2119e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 212098a9cb79SRichard Henderson { 21216fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 212298a9cb79SRichard Henderson 21232330504cSHelge Deller #ifdef CONFIG_USER_ONLY 21242330504cSHelge Deller /* We don't implement space registers in user mode. */ 21256fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 21262330504cSHelge Deller #else 2127967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2128967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 21292330504cSHelge Deller #endif 2130e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 213198a9cb79SRichard Henderson 213298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 213331234768SRichard Henderson return true; 213498a9cb79SRichard Henderson } 213598a9cb79SRichard Henderson 2136e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2137e36f27efSRichard Henderson { 2138e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2139e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY 21406fd0c7bcSRichard Henderson TCGv_i64 tmp; 2141e1b5a5edSRichard Henderson 2142e1b5a5edSRichard Henderson nullify_over(ctx); 2143e1b5a5edSRichard Henderson 2144aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21456fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21466fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2147ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2148e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2149e1b5a5edSRichard Henderson 2150e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 215131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 215231234768SRichard Henderson return nullify_end(ctx); 2153e36f27efSRichard Henderson #endif 2154e1b5a5edSRichard Henderson } 2155e1b5a5edSRichard Henderson 2156e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2157e1b5a5edSRichard Henderson { 2158e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2159e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 21606fd0c7bcSRichard Henderson TCGv_i64 tmp; 2161e1b5a5edSRichard Henderson 2162e1b5a5edSRichard Henderson nullify_over(ctx); 2163e1b5a5edSRichard Henderson 2164aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21656fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21666fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2167ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2168e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2169e1b5a5edSRichard Henderson 2170e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 217131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 217231234768SRichard Henderson return nullify_end(ctx); 2173e36f27efSRichard Henderson #endif 2174e1b5a5edSRichard Henderson } 2175e1b5a5edSRichard Henderson 2176c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2177e1b5a5edSRichard Henderson { 2178e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2179c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 21806fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2181e1b5a5edSRichard Henderson nullify_over(ctx); 2182e1b5a5edSRichard Henderson 2183c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2184aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2185ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2186e1b5a5edSRichard Henderson 2187e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 218831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 218931234768SRichard Henderson return nullify_end(ctx); 2190c603e14aSRichard Henderson #endif 2191e1b5a5edSRichard Henderson } 2192f49b3537SRichard Henderson 2193e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2194f49b3537SRichard Henderson { 2195f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2196e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2197f49b3537SRichard Henderson nullify_over(ctx); 2198f49b3537SRichard Henderson 2199e36f27efSRichard Henderson if (rfi_r) { 2200ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2201f49b3537SRichard Henderson } else { 2202ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2203f49b3537SRichard Henderson } 220431234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 220507ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 220631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2207f49b3537SRichard Henderson 220831234768SRichard Henderson return nullify_end(ctx); 2209e36f27efSRichard Henderson #endif 2210f49b3537SRichard Henderson } 22116210db05SHelge Deller 2212e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2213e36f27efSRichard Henderson { 2214e36f27efSRichard Henderson return do_rfi(ctx, false); 2215e36f27efSRichard Henderson } 2216e36f27efSRichard Henderson 2217e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2218e36f27efSRichard Henderson { 2219e36f27efSRichard Henderson return do_rfi(ctx, true); 2220e36f27efSRichard Henderson } 2221e36f27efSRichard Henderson 222296927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 22236210db05SHelge Deller { 22246210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 222596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 22266210db05SHelge Deller nullify_over(ctx); 2227ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 222831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 222931234768SRichard Henderson return nullify_end(ctx); 223096927adbSRichard Henderson #endif 22316210db05SHelge Deller } 223296927adbSRichard Henderson 223396927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 223496927adbSRichard Henderson { 223596927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 223696927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 223796927adbSRichard Henderson nullify_over(ctx); 2238ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 223996927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 224096927adbSRichard Henderson return nullify_end(ctx); 224196927adbSRichard Henderson #endif 224296927adbSRichard Henderson } 2243e1b5a5edSRichard Henderson 22444a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 22454a4554c6SHelge Deller { 22464a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22474a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY 22484a4554c6SHelge Deller nullify_over(ctx); 2249ad75a51eSRichard Henderson gen_helper_getshadowregs(tcg_env); 22504a4554c6SHelge Deller return nullify_end(ctx); 22514a4554c6SHelge Deller #endif 22524a4554c6SHelge Deller } 22534a4554c6SHelge Deller 2254deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 225598a9cb79SRichard Henderson { 2256deee69a1SRichard Henderson if (a->m) { 22576fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 22586fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 22596fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 226098a9cb79SRichard Henderson 226198a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 22626fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2263deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2264deee69a1SRichard Henderson } 226598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 226631234768SRichard Henderson return true; 226798a9cb79SRichard Henderson } 226898a9cb79SRichard Henderson 2269deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 227098a9cb79SRichard Henderson { 22716fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2272eed14219SRichard Henderson TCGv_i32 level, want; 22736fd0c7bcSRichard Henderson TCGv_i64 addr; 227498a9cb79SRichard Henderson 227598a9cb79SRichard Henderson nullify_over(ctx); 227698a9cb79SRichard Henderson 2277deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2278deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2279eed14219SRichard Henderson 2280deee69a1SRichard Henderson if (a->imm) { 228129dd6f64SRichard Henderson level = tcg_constant_i32(a->ri); 228298a9cb79SRichard Henderson } else { 2283eed14219SRichard Henderson level = tcg_temp_new_i32(); 22846fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2285eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 228698a9cb79SRichard Henderson } 228729dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2288eed14219SRichard Henderson 2289ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2290eed14219SRichard Henderson 2291deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 229231234768SRichard Henderson return nullify_end(ctx); 229398a9cb79SRichard Henderson } 229498a9cb79SRichard Henderson 2295deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 22968d6ae7fbSRichard Henderson { 22978577f354SRichard Henderson if (ctx->is_pa20) { 22988577f354SRichard Henderson return false; 22998577f354SRichard Henderson } 2300deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2301deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23026fd0c7bcSRichard Henderson TCGv_i64 addr; 23036fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 23048d6ae7fbSRichard Henderson 23058d6ae7fbSRichard Henderson nullify_over(ctx); 23068d6ae7fbSRichard Henderson 2307deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2308deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2309deee69a1SRichard Henderson if (a->addr) { 23108577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 23118d6ae7fbSRichard Henderson } else { 23128577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 23138d6ae7fbSRichard Henderson } 23148d6ae7fbSRichard Henderson 231532dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 231632dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 231731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 231831234768SRichard Henderson } 231931234768SRichard Henderson return nullify_end(ctx); 2320deee69a1SRichard Henderson #endif 23218d6ae7fbSRichard Henderson } 232263300a00SRichard Henderson 2323*eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 232463300a00SRichard Henderson { 2325deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2326deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23276fd0c7bcSRichard Henderson TCGv_i64 addr; 23286fd0c7bcSRichard Henderson TCGv_i64 ofs; 232963300a00SRichard Henderson 233063300a00SRichard Henderson nullify_over(ctx); 233163300a00SRichard Henderson 2332deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2333*eb25d10fSHelge Deller 2334*eb25d10fSHelge Deller /* 2335*eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2336*eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2337*eb25d10fSHelge Deller */ 2338*eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2339*eb25d10fSHelge Deller if (ctx->is_pa20) { 2340*eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 234163300a00SRichard Henderson } 2342*eb25d10fSHelge Deller 2343*eb25d10fSHelge Deller if (local) { 2344*eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 234563300a00SRichard Henderson } else { 2346ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 234763300a00SRichard Henderson } 234863300a00SRichard Henderson 2349*eb25d10fSHelge Deller if (a->m) { 2350*eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2351*eb25d10fSHelge Deller } 2352*eb25d10fSHelge Deller 2353*eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2354*eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2355*eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2356*eb25d10fSHelge Deller } 2357*eb25d10fSHelge Deller return nullify_end(ctx); 2358*eb25d10fSHelge Deller #endif 2359*eb25d10fSHelge Deller } 2360*eb25d10fSHelge Deller 2361*eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2362*eb25d10fSHelge Deller { 2363*eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2364*eb25d10fSHelge Deller } 2365*eb25d10fSHelge Deller 2366*eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2367*eb25d10fSHelge Deller { 2368*eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2369*eb25d10fSHelge Deller } 2370*eb25d10fSHelge Deller 2371*eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2372*eb25d10fSHelge Deller { 2373*eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2374*eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2375*eb25d10fSHelge Deller nullify_over(ctx); 2376*eb25d10fSHelge Deller 2377*eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2378*eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2379*eb25d10fSHelge Deller 238063300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 238132dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 238231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 238331234768SRichard Henderson } 238431234768SRichard Henderson return nullify_end(ctx); 2385deee69a1SRichard Henderson #endif 238663300a00SRichard Henderson } 23872dfcca9fSRichard Henderson 23886797c315SNick Hudson /* 23896797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 23906797c315SNick Hudson * See 23916797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 23926797c315SNick Hudson * page 13-9 (195/206) 23936797c315SNick Hudson */ 23946797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 23956797c315SNick Hudson { 23968577f354SRichard Henderson if (ctx->is_pa20) { 23978577f354SRichard Henderson return false; 23988577f354SRichard Henderson } 23996797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24006797c315SNick Hudson #ifndef CONFIG_USER_ONLY 24016fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 24026fd0c7bcSRichard Henderson TCGv_i64 reg; 24036797c315SNick Hudson 24046797c315SNick Hudson nullify_over(ctx); 24056797c315SNick Hudson 24066797c315SNick Hudson /* 24076797c315SNick Hudson * FIXME: 24086797c315SNick Hudson * if (not (pcxl or pcxl2)) 24096797c315SNick Hudson * return gen_illegal(ctx); 24106797c315SNick Hudson */ 24116797c315SNick Hudson 24126fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 24136fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 24146fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 24156797c315SNick Hudson 2416ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 24176797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 24186797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2419ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 24206797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 24216797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 24226797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2423d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 24246797c315SNick Hudson 24256797c315SNick Hudson reg = load_gpr(ctx, a->r); 24266797c315SNick Hudson if (a->addr) { 24278577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 24286797c315SNick Hudson } else { 24298577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 24306797c315SNick Hudson } 24316797c315SNick Hudson 24326797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 24336797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 24346797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24356797c315SNick Hudson } 24366797c315SNick Hudson return nullify_end(ctx); 24376797c315SNick Hudson #endif 24386797c315SNick Hudson } 24396797c315SNick Hudson 24408577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 24418577f354SRichard Henderson { 24428577f354SRichard Henderson if (!ctx->is_pa20) { 24438577f354SRichard Henderson return false; 24448577f354SRichard Henderson } 24458577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24468577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 24478577f354SRichard Henderson nullify_over(ctx); 24488577f354SRichard Henderson { 24498577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 24508577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 24518577f354SRichard Henderson 24528577f354SRichard Henderson if (a->data) { 24538577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 24548577f354SRichard Henderson } else { 24558577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 24568577f354SRichard Henderson } 24578577f354SRichard Henderson } 24588577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 24598577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 24608577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24618577f354SRichard Henderson } 24628577f354SRichard Henderson return nullify_end(ctx); 24638577f354SRichard Henderson #endif 24648577f354SRichard Henderson } 24658577f354SRichard Henderson 2466deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 24672dfcca9fSRichard Henderson { 2468deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2469deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24706fd0c7bcSRichard Henderson TCGv_i64 vaddr; 24716fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 24722dfcca9fSRichard Henderson 24732dfcca9fSRichard Henderson nullify_over(ctx); 24742dfcca9fSRichard Henderson 2475deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 24762dfcca9fSRichard Henderson 2477aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2478ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 24792dfcca9fSRichard Henderson 24802dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2481deee69a1SRichard Henderson if (a->m) { 2482deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 24832dfcca9fSRichard Henderson } 2484deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 24852dfcca9fSRichard Henderson 248631234768SRichard Henderson return nullify_end(ctx); 2487deee69a1SRichard Henderson #endif 24882dfcca9fSRichard Henderson } 248943a97b81SRichard Henderson 2490deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 249143a97b81SRichard Henderson { 249243a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 249343a97b81SRichard Henderson 249443a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 249543a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 249643a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 249743a97b81SRichard Henderson since the entire address space is coherent. */ 2498a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 249943a97b81SRichard Henderson 250031234768SRichard Henderson cond_free(&ctx->null_cond); 250131234768SRichard Henderson return true; 250243a97b81SRichard Henderson } 250398a9cb79SRichard Henderson 2504faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2505b2167459SRichard Henderson { 25060c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2507b2167459SRichard Henderson } 2508b2167459SRichard Henderson 2509faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2510b2167459SRichard Henderson { 25110c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2512b2167459SRichard Henderson } 2513b2167459SRichard Henderson 2514faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2515b2167459SRichard Henderson { 25160c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2517b2167459SRichard Henderson } 2518b2167459SRichard Henderson 2519faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2520b2167459SRichard Henderson { 25210c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 25220c982a28SRichard Henderson } 2523b2167459SRichard Henderson 2524faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 25250c982a28SRichard Henderson { 25260c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 25270c982a28SRichard Henderson } 25280c982a28SRichard Henderson 252963c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 25300c982a28SRichard Henderson { 25310c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 25320c982a28SRichard Henderson } 25330c982a28SRichard Henderson 253463c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25350c982a28SRichard Henderson { 25360c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 25370c982a28SRichard Henderson } 25380c982a28SRichard Henderson 253963c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25400c982a28SRichard Henderson { 25410c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 25420c982a28SRichard Henderson } 25430c982a28SRichard Henderson 254463c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25450c982a28SRichard Henderson { 25460c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 25470c982a28SRichard Henderson } 25480c982a28SRichard Henderson 254963c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 25500c982a28SRichard Henderson { 25510c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 25520c982a28SRichard Henderson } 25530c982a28SRichard Henderson 255463c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25550c982a28SRichard Henderson { 25560c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 25570c982a28SRichard Henderson } 25580c982a28SRichard Henderson 2559fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 25600c982a28SRichard Henderson { 25616fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 25620c982a28SRichard Henderson } 25630c982a28SRichard Henderson 2564fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 25650c982a28SRichard Henderson { 25666fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 25670c982a28SRichard Henderson } 25680c982a28SRichard Henderson 2569fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 25700c982a28SRichard Henderson { 25710c982a28SRichard Henderson if (a->cf == 0) { 25720c982a28SRichard Henderson unsigned r2 = a->r2; 25730c982a28SRichard Henderson unsigned r1 = a->r1; 25740c982a28SRichard Henderson unsigned rt = a->t; 25750c982a28SRichard Henderson 25767aee8189SRichard Henderson if (rt == 0) { /* NOP */ 25777aee8189SRichard Henderson cond_free(&ctx->null_cond); 25787aee8189SRichard Henderson return true; 25797aee8189SRichard Henderson } 25807aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2581b2167459SRichard Henderson if (r1 == 0) { 25826fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 25836fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2584b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2585b2167459SRichard Henderson } else { 2586b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2587b2167459SRichard Henderson } 2588b2167459SRichard Henderson cond_free(&ctx->null_cond); 258931234768SRichard Henderson return true; 2590b2167459SRichard Henderson } 25917aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 25927aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 25937aee8189SRichard Henderson * 25947aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 25957aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 25967aee8189SRichard Henderson * currently implemented as idle. 25977aee8189SRichard Henderson */ 25987aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 25997aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 26007aee8189SRichard Henderson until the next timer interrupt. */ 26017aee8189SRichard Henderson nullify_over(ctx); 26027aee8189SRichard Henderson 26037aee8189SRichard Henderson /* Advance the instruction queue. */ 2604741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 2605741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 26067aee8189SRichard Henderson nullify_set(ctx, 0); 26077aee8189SRichard Henderson 26087aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2609ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 261029dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 26117aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 26127aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 26137aee8189SRichard Henderson 26147aee8189SRichard Henderson return nullify_end(ctx); 26157aee8189SRichard Henderson } 26167aee8189SRichard Henderson #endif 26177aee8189SRichard Henderson } 26186fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 26197aee8189SRichard Henderson } 2620b2167459SRichard Henderson 2621fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2622b2167459SRichard Henderson { 26236fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 26240c982a28SRichard Henderson } 26250c982a28SRichard Henderson 2626345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 26270c982a28SRichard Henderson { 26286fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2629b2167459SRichard Henderson 26300c982a28SRichard Henderson if (a->cf) { 2631b2167459SRichard Henderson nullify_over(ctx); 2632b2167459SRichard Henderson } 26330c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26340c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2635345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 263631234768SRichard Henderson return nullify_end(ctx); 2637b2167459SRichard Henderson } 2638b2167459SRichard Henderson 2639af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2640b2167459SRichard Henderson { 26416fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2642b2167459SRichard Henderson 26430c982a28SRichard Henderson if (a->cf) { 2644b2167459SRichard Henderson nullify_over(ctx); 2645b2167459SRichard Henderson } 26460c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26470c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 26486fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64); 264931234768SRichard Henderson return nullify_end(ctx); 2650b2167459SRichard Henderson } 2651b2167459SRichard Henderson 2652af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2653b2167459SRichard Henderson { 26546fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2655b2167459SRichard Henderson 26560c982a28SRichard Henderson if (a->cf) { 2657b2167459SRichard Henderson nullify_over(ctx); 2658b2167459SRichard Henderson } 26590c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26600c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2661aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 26626fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 26636fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64); 266431234768SRichard Henderson return nullify_end(ctx); 2665b2167459SRichard Henderson } 2666b2167459SRichard Henderson 2667af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2668b2167459SRichard Henderson { 26690c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 26700c982a28SRichard Henderson } 26710c982a28SRichard Henderson 2672af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 26730c982a28SRichard Henderson { 26740c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 26750c982a28SRichard Henderson } 26760c982a28SRichard Henderson 2677af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 26780c982a28SRichard Henderson { 26796fd0c7bcSRichard Henderson TCGv_i64 tmp; 2680b2167459SRichard Henderson 2681b2167459SRichard Henderson nullify_over(ctx); 2682b2167459SRichard Henderson 2683aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 26846fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, cpu_psw_cb, 3); 2685b2167459SRichard Henderson if (!is_i) { 26866fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2687b2167459SRichard Henderson } 26886fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 26896fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 2690af240753SRichard Henderson do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false, 26916fd0c7bcSRichard Henderson is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64); 269231234768SRichard Henderson return nullify_end(ctx); 2693b2167459SRichard Henderson } 2694b2167459SRichard Henderson 2695af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2696b2167459SRichard Henderson { 26970c982a28SRichard Henderson return do_dcor(ctx, a, false); 26980c982a28SRichard Henderson } 26990c982a28SRichard Henderson 2700af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 27010c982a28SRichard Henderson { 27020c982a28SRichard Henderson return do_dcor(ctx, a, true); 27030c982a28SRichard Henderson } 27040c982a28SRichard Henderson 27050c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 27060c982a28SRichard Henderson { 2707a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 27086fd0c7bcSRichard Henderson TCGv_i64 cout; 2709b2167459SRichard Henderson 2710b2167459SRichard Henderson nullify_over(ctx); 2711b2167459SRichard Henderson 27120c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 27130c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2714b2167459SRichard Henderson 2715aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2716aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2717aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2718aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2719b2167459SRichard Henderson 2720b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 27216fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 27226fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2723b2167459SRichard Henderson 272472ca8753SRichard Henderson /* 272572ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 272672ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 272772ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 272872ca8753SRichard Henderson * proper inputs to the addition without movcond. 272972ca8753SRichard Henderson */ 27306fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 27316fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 27326fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 273372ca8753SRichard Henderson 2734a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2735a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2736a4db4a78SRichard Henderson addc, ctx->zero); 2737b2167459SRichard Henderson 2738b2167459SRichard Henderson /* Write back the result register. */ 27390c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2740b2167459SRichard Henderson 2741b2167459SRichard Henderson /* Write back PSW[CB]. */ 27426fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 27436fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2744b2167459SRichard Henderson 2745b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 274672ca8753SRichard Henderson cout = get_psw_carry(ctx, false); 27476fd0c7bcSRichard Henderson tcg_gen_neg_i64(cpu_psw_v, cout); 27486fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2749b2167459SRichard Henderson 2750b2167459SRichard Henderson /* Install the new nullification. */ 27510c982a28SRichard Henderson if (a->cf) { 27526fd0c7bcSRichard Henderson TCGv_i64 sv = NULL; 2753b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2754b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 2755b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 2756b2167459SRichard Henderson } 2757a751eb31SRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv); 2758b2167459SRichard Henderson } 2759b2167459SRichard Henderson 276031234768SRichard Henderson return nullify_end(ctx); 2761b2167459SRichard Henderson } 2762b2167459SRichard Henderson 27630588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2764b2167459SRichard Henderson { 27650588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 27660588e061SRichard Henderson } 27670588e061SRichard Henderson 27680588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 27690588e061SRichard Henderson { 27700588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 27710588e061SRichard Henderson } 27720588e061SRichard Henderson 27730588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 27740588e061SRichard Henderson { 27750588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 27760588e061SRichard Henderson } 27770588e061SRichard Henderson 27780588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 27790588e061SRichard Henderson { 27800588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 27810588e061SRichard Henderson } 27820588e061SRichard Henderson 27830588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 27840588e061SRichard Henderson { 27850588e061SRichard Henderson return do_sub_imm(ctx, a, false); 27860588e061SRichard Henderson } 27870588e061SRichard Henderson 27880588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 27890588e061SRichard Henderson { 27900588e061SRichard Henderson return do_sub_imm(ctx, a, true); 27910588e061SRichard Henderson } 27920588e061SRichard Henderson 2793345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 27940588e061SRichard Henderson { 27956fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 2796b2167459SRichard Henderson 27970588e061SRichard Henderson if (a->cf) { 2798b2167459SRichard Henderson nullify_over(ctx); 2799b2167459SRichard Henderson } 2800b2167459SRichard Henderson 28016fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 28020588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 2803345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2804b2167459SRichard Henderson 280531234768SRichard Henderson return nullify_end(ctx); 2806b2167459SRichard Henderson } 2807b2167459SRichard Henderson 28080843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 28090843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 28100843563fSRichard Henderson { 28110843563fSRichard Henderson TCGv_i64 r1, r2, dest; 28120843563fSRichard Henderson 28130843563fSRichard Henderson if (!ctx->is_pa20) { 28140843563fSRichard Henderson return false; 28150843563fSRichard Henderson } 28160843563fSRichard Henderson 28170843563fSRichard Henderson nullify_over(ctx); 28180843563fSRichard Henderson 28190843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 28200843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 28210843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 28220843563fSRichard Henderson 28230843563fSRichard Henderson fn(dest, r1, r2); 28240843563fSRichard Henderson save_gpr(ctx, a->t, dest); 28250843563fSRichard Henderson 28260843563fSRichard Henderson return nullify_end(ctx); 28270843563fSRichard Henderson } 28280843563fSRichard Henderson 2829151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 2830151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 2831151f309bSRichard Henderson { 2832151f309bSRichard Henderson TCGv_i64 r, dest; 2833151f309bSRichard Henderson 2834151f309bSRichard Henderson if (!ctx->is_pa20) { 2835151f309bSRichard Henderson return false; 2836151f309bSRichard Henderson } 2837151f309bSRichard Henderson 2838151f309bSRichard Henderson nullify_over(ctx); 2839151f309bSRichard Henderson 2840151f309bSRichard Henderson r = load_gpr(ctx, a->r); 2841151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 2842151f309bSRichard Henderson 2843151f309bSRichard Henderson fn(dest, r, a->i); 2844151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 2845151f309bSRichard Henderson 2846151f309bSRichard Henderson return nullify_end(ctx); 2847151f309bSRichard Henderson } 2848151f309bSRichard Henderson 28493bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 28503bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 28513bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 28523bbb8e48SRichard Henderson { 28533bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 28543bbb8e48SRichard Henderson 28553bbb8e48SRichard Henderson if (!ctx->is_pa20) { 28563bbb8e48SRichard Henderson return false; 28573bbb8e48SRichard Henderson } 28583bbb8e48SRichard Henderson 28593bbb8e48SRichard Henderson nullify_over(ctx); 28603bbb8e48SRichard Henderson 28613bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 28623bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 28633bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 28643bbb8e48SRichard Henderson 28653bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 28663bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 28673bbb8e48SRichard Henderson 28683bbb8e48SRichard Henderson return nullify_end(ctx); 28693bbb8e48SRichard Henderson } 28703bbb8e48SRichard Henderson 28710843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 28720843563fSRichard Henderson { 28730843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 28740843563fSRichard Henderson } 28750843563fSRichard Henderson 28760843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 28770843563fSRichard Henderson { 28780843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 28790843563fSRichard Henderson } 28800843563fSRichard Henderson 28810843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 28820843563fSRichard Henderson { 28830843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 28840843563fSRichard Henderson } 28850843563fSRichard Henderson 28861b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 28871b3cb7c8SRichard Henderson { 28881b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 28891b3cb7c8SRichard Henderson } 28901b3cb7c8SRichard Henderson 2891151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 2892151f309bSRichard Henderson { 2893151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 2894151f309bSRichard Henderson } 2895151f309bSRichard Henderson 2896151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 2897151f309bSRichard Henderson { 2898151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 2899151f309bSRichard Henderson } 2900151f309bSRichard Henderson 2901151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 2902151f309bSRichard Henderson { 2903151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 2904151f309bSRichard Henderson } 2905151f309bSRichard Henderson 29063bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 29073bbb8e48SRichard Henderson { 29083bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 29093bbb8e48SRichard Henderson } 29103bbb8e48SRichard Henderson 29113bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 29123bbb8e48SRichard Henderson { 29133bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 29143bbb8e48SRichard Henderson } 29153bbb8e48SRichard Henderson 291610c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 291710c9e58dSRichard Henderson { 291810c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 291910c9e58dSRichard Henderson } 292010c9e58dSRichard Henderson 292110c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 292210c9e58dSRichard Henderson { 292310c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 292410c9e58dSRichard Henderson } 292510c9e58dSRichard Henderson 292610c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 292710c9e58dSRichard Henderson { 292810c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 292910c9e58dSRichard Henderson } 293010c9e58dSRichard Henderson 2931c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2932c2a7ee3fSRichard Henderson { 2933c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 2934c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2935c2a7ee3fSRichard Henderson 2936c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 2937c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 2938c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 2939c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2940c2a7ee3fSRichard Henderson } 2941c2a7ee3fSRichard Henderson 2942c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 2943c2a7ee3fSRichard Henderson { 2944c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 2945c2a7ee3fSRichard Henderson } 2946c2a7ee3fSRichard Henderson 2947c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2948c2a7ee3fSRichard Henderson { 2949c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 2950c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2951c2a7ee3fSRichard Henderson 2952c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 2953c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 2954c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 2955c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2956c2a7ee3fSRichard Henderson } 2957c2a7ee3fSRichard Henderson 2958c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 2959c2a7ee3fSRichard Henderson { 2960c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 2961c2a7ee3fSRichard Henderson } 2962c2a7ee3fSRichard Henderson 2963c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2964c2a7ee3fSRichard Henderson { 2965c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2966c2a7ee3fSRichard Henderson 2967c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 2968c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 2969c2a7ee3fSRichard Henderson } 2970c2a7ee3fSRichard Henderson 2971c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 2972c2a7ee3fSRichard Henderson { 2973c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 2974c2a7ee3fSRichard Henderson } 2975c2a7ee3fSRichard Henderson 2976c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2977c2a7ee3fSRichard Henderson { 2978c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 2979c2a7ee3fSRichard Henderson } 2980c2a7ee3fSRichard Henderson 2981c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 2982c2a7ee3fSRichard Henderson { 2983c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 2984c2a7ee3fSRichard Henderson } 2985c2a7ee3fSRichard Henderson 29864e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 29874e7abdb1SRichard Henderson { 29884e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 29894e7abdb1SRichard Henderson 29904e7abdb1SRichard Henderson if (!ctx->is_pa20) { 29914e7abdb1SRichard Henderson return false; 29924e7abdb1SRichard Henderson } 29934e7abdb1SRichard Henderson 29944e7abdb1SRichard Henderson nullify_over(ctx); 29954e7abdb1SRichard Henderson 29964e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 29974e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 29984e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 29994e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 30004e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 30014e7abdb1SRichard Henderson 30024e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 30034e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 30044e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 30054e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 30064e7abdb1SRichard Henderson 30074e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 30084e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 30094e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 30104e7abdb1SRichard Henderson 30114e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 30124e7abdb1SRichard Henderson return nullify_end(ctx); 30134e7abdb1SRichard Henderson } 30144e7abdb1SRichard Henderson 30151cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 301696d6407fSRichard Henderson { 3017b5caa17cSRichard Henderson if (ctx->is_pa20) { 3018b5caa17cSRichard Henderson /* 3019b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3020b5caa17cSRichard Henderson * Any base modification still occurs. 3021b5caa17cSRichard Henderson */ 3022b5caa17cSRichard Henderson if (a->t == 0) { 3023b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3024b5caa17cSRichard Henderson } 3025b5caa17cSRichard Henderson } else if (a->size > MO_32) { 30260786a3b6SHelge Deller return gen_illegal(ctx); 3027c53e401eSRichard Henderson } 30281cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 30291cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 303096d6407fSRichard Henderson } 303196d6407fSRichard Henderson 30321cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 303396d6407fSRichard Henderson { 30341cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3035c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 30360786a3b6SHelge Deller return gen_illegal(ctx); 303796d6407fSRichard Henderson } 3038c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 30390786a3b6SHelge Deller } 304096d6407fSRichard Henderson 30411cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 304296d6407fSRichard Henderson { 3043b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3044a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 30456fd0c7bcSRichard Henderson TCGv_i64 addr; 304696d6407fSRichard Henderson 3047c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 304851416c4eSRichard Henderson return gen_illegal(ctx); 304951416c4eSRichard Henderson } 305051416c4eSRichard Henderson 305196d6407fSRichard Henderson nullify_over(ctx); 305296d6407fSRichard Henderson 30531cd012a5SRichard Henderson if (a->m) { 305486f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 305586f8d05fSRichard Henderson we see the result of the load. */ 3056aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 305796d6407fSRichard Henderson } else { 30581cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 305996d6407fSRichard Henderson } 306096d6407fSRichard Henderson 30611cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0, 30621cd012a5SRichard Henderson a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX); 3063b1af755cSRichard Henderson 3064b1af755cSRichard Henderson /* 3065b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3066b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3067b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3068b1af755cSRichard Henderson * 3069b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3070b1af755cSRichard Henderson * with the ,co completer. 3071b1af755cSRichard Henderson */ 3072b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3073b1af755cSRichard Henderson 3074a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3075b1af755cSRichard Henderson 30761cd012a5SRichard Henderson if (a->m) { 30771cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 307896d6407fSRichard Henderson } 30791cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 308096d6407fSRichard Henderson 308131234768SRichard Henderson return nullify_end(ctx); 308296d6407fSRichard Henderson } 308396d6407fSRichard Henderson 30841cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 308596d6407fSRichard Henderson { 30866fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 30876fd0c7bcSRichard Henderson TCGv_i64 addr; 308896d6407fSRichard Henderson 308996d6407fSRichard Henderson nullify_over(ctx); 309096d6407fSRichard Henderson 30911cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 309286f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 30931cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 30941cd012a5SRichard Henderson if (a->a) { 3095f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3096ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3097f9f46db4SEmilio G. Cota } else { 3098ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3099f9f46db4SEmilio G. Cota } 3100f9f46db4SEmilio G. Cota } else { 3101f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3102ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 310396d6407fSRichard Henderson } else { 3104ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 310596d6407fSRichard Henderson } 3106f9f46db4SEmilio G. Cota } 31071cd012a5SRichard Henderson if (a->m) { 31086fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 31091cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 311096d6407fSRichard Henderson } 311196d6407fSRichard Henderson 311231234768SRichard Henderson return nullify_end(ctx); 311396d6407fSRichard Henderson } 311496d6407fSRichard Henderson 311525460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 311625460fc5SRichard Henderson { 31176fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31186fd0c7bcSRichard Henderson TCGv_i64 addr; 311925460fc5SRichard Henderson 312025460fc5SRichard Henderson if (!ctx->is_pa20) { 312125460fc5SRichard Henderson return false; 312225460fc5SRichard Henderson } 312325460fc5SRichard Henderson nullify_over(ctx); 312425460fc5SRichard Henderson 312525460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 312625460fc5SRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 312725460fc5SRichard Henderson val = load_gpr(ctx, a->r); 312825460fc5SRichard Henderson if (a->a) { 312925460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 313025460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 313125460fc5SRichard Henderson } else { 313225460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 313325460fc5SRichard Henderson } 313425460fc5SRichard Henderson } else { 313525460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 313625460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 313725460fc5SRichard Henderson } else { 313825460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 313925460fc5SRichard Henderson } 314025460fc5SRichard Henderson } 314125460fc5SRichard Henderson if (a->m) { 31426fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 314325460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 314425460fc5SRichard Henderson } 314525460fc5SRichard Henderson 314625460fc5SRichard Henderson return nullify_end(ctx); 314725460fc5SRichard Henderson } 314825460fc5SRichard Henderson 31491cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3150d0a851ccSRichard Henderson { 3151d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3152d0a851ccSRichard Henderson 3153d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3154d0a851ccSRichard Henderson ctx->mmu_idx = MMU_PHYS_IDX; 31551cd012a5SRichard Henderson trans_ld(ctx, a); 3156d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 315731234768SRichard Henderson return true; 3158d0a851ccSRichard Henderson } 3159d0a851ccSRichard Henderson 31601cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3161d0a851ccSRichard Henderson { 3162d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3163d0a851ccSRichard Henderson 3164d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3165d0a851ccSRichard Henderson ctx->mmu_idx = MMU_PHYS_IDX; 31661cd012a5SRichard Henderson trans_st(ctx, a); 3167d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 316831234768SRichard Henderson return true; 3169d0a851ccSRichard Henderson } 317095412a61SRichard Henderson 31710588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3172b2167459SRichard Henderson { 31736fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3174b2167459SRichard Henderson 31756fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 31760588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3177b2167459SRichard Henderson cond_free(&ctx->null_cond); 317831234768SRichard Henderson return true; 3179b2167459SRichard Henderson } 3180b2167459SRichard Henderson 31810588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3182b2167459SRichard Henderson { 31836fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 31846fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3185b2167459SRichard Henderson 31866fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3187b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3188b2167459SRichard Henderson cond_free(&ctx->null_cond); 318931234768SRichard Henderson return true; 3190b2167459SRichard Henderson } 3191b2167459SRichard Henderson 31920588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3193b2167459SRichard Henderson { 31946fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3195b2167459SRichard Henderson 3196b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3197d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 31980588e061SRichard Henderson if (a->b == 0) { 31996fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3200b2167459SRichard Henderson } else { 32016fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3202b2167459SRichard Henderson } 32030588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3204b2167459SRichard Henderson cond_free(&ctx->null_cond); 320531234768SRichard Henderson return true; 3206b2167459SRichard Henderson } 3207b2167459SRichard Henderson 32086fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3209e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 321098cd9ca7SRichard Henderson { 32116fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 321298cd9ca7SRichard Henderson DisasCond cond; 321398cd9ca7SRichard Henderson 321498cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3215aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 321698cd9ca7SRichard Henderson 32176fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 321898cd9ca7SRichard Henderson 3219f764718dSRichard Henderson sv = NULL; 3220b47a4a02SSven Schnelle if (cond_need_sv(c)) { 322198cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 322298cd9ca7SRichard Henderson } 322398cd9ca7SRichard Henderson 32244fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 322501afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 322698cd9ca7SRichard Henderson } 322798cd9ca7SRichard Henderson 322801afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 322998cd9ca7SRichard Henderson { 3230e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3231e9efd4bcSRichard Henderson return false; 3232e9efd4bcSRichard Henderson } 323301afb7beSRichard Henderson nullify_over(ctx); 3234e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3235e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 323601afb7beSRichard Henderson } 323701afb7beSRichard Henderson 323801afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 323901afb7beSRichard Henderson { 3240c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3241c65c3ee1SRichard Henderson return false; 3242c65c3ee1SRichard Henderson } 324301afb7beSRichard Henderson nullify_over(ctx); 32446fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3245c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 324601afb7beSRichard Henderson } 324701afb7beSRichard Henderson 32486fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 324901afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 325001afb7beSRichard Henderson { 32516fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 325298cd9ca7SRichard Henderson DisasCond cond; 3253bdcccc17SRichard Henderson bool d = false; 325498cd9ca7SRichard Henderson 3255f25d3160SRichard Henderson /* 3256f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3257f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3258f25d3160SRichard Henderson */ 3259f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3260f25d3160SRichard Henderson d = c >= 5; 3261f25d3160SRichard Henderson if (d) { 3262f25d3160SRichard Henderson c &= 3; 3263f25d3160SRichard Henderson } 3264f25d3160SRichard Henderson } 3265f25d3160SRichard Henderson 326698cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3267aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3268f764718dSRichard Henderson sv = NULL; 3269bdcccc17SRichard Henderson cb_cond = NULL; 327098cd9ca7SRichard Henderson 3271b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3272aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3273aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3274bdcccc17SRichard Henderson 32756fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 32766fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 32776fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 32786fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3279bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3280b47a4a02SSven Schnelle } else { 32816fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3282b47a4a02SSven Schnelle } 3283b47a4a02SSven Schnelle if (cond_need_sv(c)) { 328498cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 328598cd9ca7SRichard Henderson } 328698cd9ca7SRichard Henderson 3287a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 328843675d20SSven Schnelle save_gpr(ctx, r, dest); 328901afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 329098cd9ca7SRichard Henderson } 329198cd9ca7SRichard Henderson 329201afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 329398cd9ca7SRichard Henderson { 329401afb7beSRichard Henderson nullify_over(ctx); 329501afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 329601afb7beSRichard Henderson } 329701afb7beSRichard Henderson 329801afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 329901afb7beSRichard Henderson { 330001afb7beSRichard Henderson nullify_over(ctx); 33016fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 330201afb7beSRichard Henderson } 330301afb7beSRichard Henderson 330401afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 330501afb7beSRichard Henderson { 33066fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 330798cd9ca7SRichard Henderson DisasCond cond; 330898cd9ca7SRichard Henderson 330998cd9ca7SRichard Henderson nullify_over(ctx); 331098cd9ca7SRichard Henderson 3311aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 331201afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 331384e224d4SRichard Henderson if (cond_need_ext(ctx, a->d)) { 33141e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 33156fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 33166fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 33171e9ab9fbSRichard Henderson } else { 33186fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 33191e9ab9fbSRichard Henderson } 332098cd9ca7SRichard Henderson 33211e9ab9fbSRichard Henderson cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 332201afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 332398cd9ca7SRichard Henderson } 332498cd9ca7SRichard Henderson 332501afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 332698cd9ca7SRichard Henderson { 33276fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 332801afb7beSRichard Henderson DisasCond cond; 33291e9ab9fbSRichard Henderson int p; 333001afb7beSRichard Henderson 333101afb7beSRichard Henderson nullify_over(ctx); 333201afb7beSRichard Henderson 3333aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 333401afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 333584e224d4SRichard Henderson p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0); 33366fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, tcg_r, p); 333701afb7beSRichard Henderson 333801afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 333901afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 334001afb7beSRichard Henderson } 334101afb7beSRichard Henderson 334201afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 334301afb7beSRichard Henderson { 33446fd0c7bcSRichard Henderson TCGv_i64 dest; 334598cd9ca7SRichard Henderson DisasCond cond; 334698cd9ca7SRichard Henderson 334798cd9ca7SRichard Henderson nullify_over(ctx); 334898cd9ca7SRichard Henderson 334901afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 335001afb7beSRichard Henderson if (a->r1 == 0) { 33516fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 335298cd9ca7SRichard Henderson } else { 33536fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 335498cd9ca7SRichard Henderson } 335598cd9ca7SRichard Henderson 33564fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 33574fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 335801afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 335901afb7beSRichard Henderson } 336001afb7beSRichard Henderson 336101afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 336201afb7beSRichard Henderson { 33636fd0c7bcSRichard Henderson TCGv_i64 dest; 336401afb7beSRichard Henderson DisasCond cond; 336501afb7beSRichard Henderson 336601afb7beSRichard Henderson nullify_over(ctx); 336701afb7beSRichard Henderson 336801afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 33696fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 337001afb7beSRichard Henderson 33714fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 33724fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 337301afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 337498cd9ca7SRichard Henderson } 337598cd9ca7SRichard Henderson 3376f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 33770b1347d2SRichard Henderson { 33786fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 33790b1347d2SRichard Henderson 3380f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3381f7b775a9SRichard Henderson return false; 3382f7b775a9SRichard Henderson } 338330878590SRichard Henderson if (a->c) { 33840b1347d2SRichard Henderson nullify_over(ctx); 33850b1347d2SRichard Henderson } 33860b1347d2SRichard Henderson 338730878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3388f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 338930878590SRichard Henderson if (a->r1 == 0) { 3390f7b775a9SRichard Henderson if (a->d) { 33916fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3392f7b775a9SRichard Henderson } else { 3393aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3394f7b775a9SRichard Henderson 33956fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 33966fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 33976fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3398f7b775a9SRichard Henderson } 339930878590SRichard Henderson } else if (a->r1 == a->r2) { 3400f7b775a9SRichard Henderson if (a->d) { 34016fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3402f7b775a9SRichard Henderson } else { 34030b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3404e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3405e1d635e8SRichard Henderson 34066fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 34076fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3408f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3409e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 34106fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3411f7b775a9SRichard Henderson } 3412f7b775a9SRichard Henderson } else { 34136fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3414f7b775a9SRichard Henderson 3415f7b775a9SRichard Henderson if (a->d) { 3416aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3417aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3418f7b775a9SRichard Henderson 34196fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 34206fd0c7bcSRichard Henderson tcg_gen_shl_i64(t, src2, n); 34216fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 34226fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src1, cpu_sar); 34236fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 34240b1347d2SRichard Henderson } else { 34250b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 34260b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 34270b1347d2SRichard Henderson 34286fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3429967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3430967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 34310b1347d2SRichard Henderson } 3432f7b775a9SRichard Henderson } 343330878590SRichard Henderson save_gpr(ctx, a->t, dest); 34340b1347d2SRichard Henderson 34350b1347d2SRichard Henderson /* Install the new nullification. */ 34360b1347d2SRichard Henderson cond_free(&ctx->null_cond); 343730878590SRichard Henderson if (a->c) { 34384fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 34390b1347d2SRichard Henderson } 344031234768SRichard Henderson return nullify_end(ctx); 34410b1347d2SRichard Henderson } 34420b1347d2SRichard Henderson 3443f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 34440b1347d2SRichard Henderson { 3445f7b775a9SRichard Henderson unsigned width, sa; 34466fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 34470b1347d2SRichard Henderson 3448f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3449f7b775a9SRichard Henderson return false; 3450f7b775a9SRichard Henderson } 345130878590SRichard Henderson if (a->c) { 34520b1347d2SRichard Henderson nullify_over(ctx); 34530b1347d2SRichard Henderson } 34540b1347d2SRichard Henderson 3455f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3456f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3457f7b775a9SRichard Henderson 345830878590SRichard Henderson dest = dest_gpr(ctx, a->t); 345930878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 346005bfd4dbSRichard Henderson if (a->r1 == 0) { 34616fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3462c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 34636fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3464f7b775a9SRichard Henderson } else { 3465f7b775a9SRichard Henderson assert(!a->d); 3466f7b775a9SRichard Henderson if (a->r1 == a->r2) { 34670b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 34686fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 34690b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 34706fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 34710b1347d2SRichard Henderson } else { 3472967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3473967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 34740b1347d2SRichard Henderson } 3475f7b775a9SRichard Henderson } 347630878590SRichard Henderson save_gpr(ctx, a->t, dest); 34770b1347d2SRichard Henderson 34780b1347d2SRichard Henderson /* Install the new nullification. */ 34790b1347d2SRichard Henderson cond_free(&ctx->null_cond); 348030878590SRichard Henderson if (a->c) { 34814fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 34820b1347d2SRichard Henderson } 348331234768SRichard Henderson return nullify_end(ctx); 34840b1347d2SRichard Henderson } 34850b1347d2SRichard Henderson 3486bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 34870b1347d2SRichard Henderson { 3488bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 34896fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 34900b1347d2SRichard Henderson 3491bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3492bd792da3SRichard Henderson return false; 3493bd792da3SRichard Henderson } 349430878590SRichard Henderson if (a->c) { 34950b1347d2SRichard Henderson nullify_over(ctx); 34960b1347d2SRichard Henderson } 34970b1347d2SRichard Henderson 349830878590SRichard Henderson dest = dest_gpr(ctx, a->t); 349930878590SRichard Henderson src = load_gpr(ctx, a->r); 3500aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 35010b1347d2SRichard Henderson 35020b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 35036fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 35046fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3505d781cb77SRichard Henderson 350630878590SRichard Henderson if (a->se) { 3507bd792da3SRichard Henderson if (!a->d) { 35086fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3509bd792da3SRichard Henderson src = dest; 3510bd792da3SRichard Henderson } 35116fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 35126fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 35130b1347d2SRichard Henderson } else { 3514bd792da3SRichard Henderson if (!a->d) { 35156fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3516bd792da3SRichard Henderson src = dest; 3517bd792da3SRichard Henderson } 35186fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 35196fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 35200b1347d2SRichard Henderson } 352130878590SRichard Henderson save_gpr(ctx, a->t, dest); 35220b1347d2SRichard Henderson 35230b1347d2SRichard Henderson /* Install the new nullification. */ 35240b1347d2SRichard Henderson cond_free(&ctx->null_cond); 352530878590SRichard Henderson if (a->c) { 3526bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35270b1347d2SRichard Henderson } 352831234768SRichard Henderson return nullify_end(ctx); 35290b1347d2SRichard Henderson } 35300b1347d2SRichard Henderson 3531bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 35320b1347d2SRichard Henderson { 3533bd792da3SRichard Henderson unsigned len, cpos, width; 35346fd0c7bcSRichard Henderson TCGv_i64 dest, src; 35350b1347d2SRichard Henderson 3536bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3537bd792da3SRichard Henderson return false; 3538bd792da3SRichard Henderson } 353930878590SRichard Henderson if (a->c) { 35400b1347d2SRichard Henderson nullify_over(ctx); 35410b1347d2SRichard Henderson } 35420b1347d2SRichard Henderson 3543bd792da3SRichard Henderson len = a->len; 3544bd792da3SRichard Henderson width = a->d ? 64 : 32; 3545bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3546bd792da3SRichard Henderson if (cpos + len > width) { 3547bd792da3SRichard Henderson len = width - cpos; 3548bd792da3SRichard Henderson } 3549bd792da3SRichard Henderson 355030878590SRichard Henderson dest = dest_gpr(ctx, a->t); 355130878590SRichard Henderson src = load_gpr(ctx, a->r); 355230878590SRichard Henderson if (a->se) { 35536fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 35540b1347d2SRichard Henderson } else { 35556fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 35560b1347d2SRichard Henderson } 355730878590SRichard Henderson save_gpr(ctx, a->t, dest); 35580b1347d2SRichard Henderson 35590b1347d2SRichard Henderson /* Install the new nullification. */ 35600b1347d2SRichard Henderson cond_free(&ctx->null_cond); 356130878590SRichard Henderson if (a->c) { 3562bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35630b1347d2SRichard Henderson } 356431234768SRichard Henderson return nullify_end(ctx); 35650b1347d2SRichard Henderson } 35660b1347d2SRichard Henderson 356772ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 35680b1347d2SRichard Henderson { 356972ae4f2bSRichard Henderson unsigned len, width; 3570c53e401eSRichard Henderson uint64_t mask0, mask1; 35716fd0c7bcSRichard Henderson TCGv_i64 dest; 35720b1347d2SRichard Henderson 357372ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 357472ae4f2bSRichard Henderson return false; 357572ae4f2bSRichard Henderson } 357630878590SRichard Henderson if (a->c) { 35770b1347d2SRichard Henderson nullify_over(ctx); 35780b1347d2SRichard Henderson } 357972ae4f2bSRichard Henderson 358072ae4f2bSRichard Henderson len = a->len; 358172ae4f2bSRichard Henderson width = a->d ? 64 : 32; 358272ae4f2bSRichard Henderson if (a->cpos + len > width) { 358372ae4f2bSRichard Henderson len = width - a->cpos; 35840b1347d2SRichard Henderson } 35850b1347d2SRichard Henderson 358630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 358730878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 358830878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 35890b1347d2SRichard Henderson 359030878590SRichard Henderson if (a->nz) { 35916fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 35926fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 35936fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 35940b1347d2SRichard Henderson } else { 35956fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 35960b1347d2SRichard Henderson } 359730878590SRichard Henderson save_gpr(ctx, a->t, dest); 35980b1347d2SRichard Henderson 35990b1347d2SRichard Henderson /* Install the new nullification. */ 36000b1347d2SRichard Henderson cond_free(&ctx->null_cond); 360130878590SRichard Henderson if (a->c) { 360272ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36030b1347d2SRichard Henderson } 360431234768SRichard Henderson return nullify_end(ctx); 36050b1347d2SRichard Henderson } 36060b1347d2SRichard Henderson 360772ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 36080b1347d2SRichard Henderson { 360930878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 361072ae4f2bSRichard Henderson unsigned len, width; 36116fd0c7bcSRichard Henderson TCGv_i64 dest, val; 36120b1347d2SRichard Henderson 361372ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 361472ae4f2bSRichard Henderson return false; 361572ae4f2bSRichard Henderson } 361630878590SRichard Henderson if (a->c) { 36170b1347d2SRichard Henderson nullify_over(ctx); 36180b1347d2SRichard Henderson } 361972ae4f2bSRichard Henderson 362072ae4f2bSRichard Henderson len = a->len; 362172ae4f2bSRichard Henderson width = a->d ? 64 : 32; 362272ae4f2bSRichard Henderson if (a->cpos + len > width) { 362372ae4f2bSRichard Henderson len = width - a->cpos; 36240b1347d2SRichard Henderson } 36250b1347d2SRichard Henderson 362630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 362730878590SRichard Henderson val = load_gpr(ctx, a->r); 36280b1347d2SRichard Henderson if (rs == 0) { 36296fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 36300b1347d2SRichard Henderson } else { 36316fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 36320b1347d2SRichard Henderson } 363330878590SRichard Henderson save_gpr(ctx, a->t, dest); 36340b1347d2SRichard Henderson 36350b1347d2SRichard Henderson /* Install the new nullification. */ 36360b1347d2SRichard Henderson cond_free(&ctx->null_cond); 363730878590SRichard Henderson if (a->c) { 363872ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36390b1347d2SRichard Henderson } 364031234768SRichard Henderson return nullify_end(ctx); 36410b1347d2SRichard Henderson } 36420b1347d2SRichard Henderson 364372ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 36446fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 36450b1347d2SRichard Henderson { 36460b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 364772ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 36486fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3649c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 36500b1347d2SRichard Henderson 36510b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3652aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3653aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 36540b1347d2SRichard Henderson 36550b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 36566fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 36576fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 36580b1347d2SRichard Henderson 3659aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 36606fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 36616fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 36620b1347d2SRichard Henderson if (rs) { 36636fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 36646fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 36656fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 36666fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 36670b1347d2SRichard Henderson } else { 36686fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 36690b1347d2SRichard Henderson } 36700b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 36710b1347d2SRichard Henderson 36720b1347d2SRichard Henderson /* Install the new nullification. */ 36730b1347d2SRichard Henderson cond_free(&ctx->null_cond); 36740b1347d2SRichard Henderson if (c) { 367572ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 36760b1347d2SRichard Henderson } 367731234768SRichard Henderson return nullify_end(ctx); 36780b1347d2SRichard Henderson } 36790b1347d2SRichard Henderson 368072ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 368130878590SRichard Henderson { 368272ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 368372ae4f2bSRichard Henderson return false; 368472ae4f2bSRichard Henderson } 3685a6deecceSSven Schnelle if (a->c) { 3686a6deecceSSven Schnelle nullify_over(ctx); 3687a6deecceSSven Schnelle } 368872ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 368972ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 369030878590SRichard Henderson } 369130878590SRichard Henderson 369272ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 369330878590SRichard Henderson { 369472ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 369572ae4f2bSRichard Henderson return false; 369672ae4f2bSRichard Henderson } 3697a6deecceSSven Schnelle if (a->c) { 3698a6deecceSSven Schnelle nullify_over(ctx); 3699a6deecceSSven Schnelle } 370072ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 37016fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 370230878590SRichard Henderson } 37030b1347d2SRichard Henderson 37048340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 370598cd9ca7SRichard Henderson { 37066fd0c7bcSRichard Henderson TCGv_i64 tmp; 370798cd9ca7SRichard Henderson 3708c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 370998cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 371098cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 371198cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 371298cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 371398cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 371498cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 371598cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 371698cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 37178340f534SRichard Henderson if (a->b == 0) { 37188340f534SRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 371998cd9ca7SRichard Henderson } 3720c301f34eSRichard Henderson #else 3721c301f34eSRichard Henderson nullify_over(ctx); 3722660eefe1SRichard Henderson #endif 3723660eefe1SRichard Henderson 3724aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37256fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp); 3726660eefe1SRichard Henderson tmp = do_ibranch_priv(ctx, tmp); 3727c301f34eSRichard Henderson 3728c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 37298340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3730c301f34eSRichard Henderson #else 3731c301f34eSRichard Henderson TCGv_i64 new_spc = tcg_temp_new_i64(); 3732c301f34eSRichard Henderson 37338340f534SRichard Henderson load_spr(ctx, new_spc, a->sp); 37348340f534SRichard Henderson if (a->l) { 3735741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); 3736c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); 3737c301f34eSRichard Henderson } 37388340f534SRichard Henderson if (a->n && use_nullify_skip(ctx)) { 3739a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 37406fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 3741a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3742c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, new_spc); 3743c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); 3744c301f34eSRichard Henderson } else { 3745741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3746c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3747c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3748c301f34eSRichard Henderson } 3749a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3750c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, new_spc); 37518340f534SRichard Henderson nullify_set(ctx, a->n); 3752c301f34eSRichard Henderson } 3753c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 375431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 375531234768SRichard Henderson return nullify_end(ctx); 3756c301f34eSRichard Henderson #endif 375798cd9ca7SRichard Henderson } 375898cd9ca7SRichard Henderson 37598340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 376098cd9ca7SRichard Henderson { 37618340f534SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n); 376298cd9ca7SRichard Henderson } 376398cd9ca7SRichard Henderson 37648340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 376543e05652SRichard Henderson { 3766c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, a->disp); 376743e05652SRichard Henderson 37686e5f5300SSven Schnelle nullify_over(ctx); 37696e5f5300SSven Schnelle 377043e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 377143e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 377243e05652SRichard Henderson * expensive to track. Real hardware will trap for 377343e05652SRichard Henderson * b gateway 377443e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 377543e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 377643e05652SRichard Henderson * diagnose the security hole 377743e05652SRichard Henderson * b gateway 377843e05652SRichard Henderson * b evil 377943e05652SRichard Henderson * in which instructions at evil would run with increased privs. 378043e05652SRichard Henderson */ 378143e05652SRichard Henderson if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) { 378243e05652SRichard Henderson return gen_illegal(ctx); 378343e05652SRichard Henderson } 378443e05652SRichard Henderson 378543e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 378643e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 3787b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(ctx->cs); 378843e05652SRichard Henderson int type = hppa_artype_for_page(env, ctx->base.pc_next); 378943e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 379043e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 379143e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 379243e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 379343e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 379443e05652SRichard Henderson if (type < 0) { 379531234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 379631234768SRichard Henderson return true; 379743e05652SRichard Henderson } 379843e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 379943e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 380043e05652SRichard Henderson dest = deposit32(dest, 0, 2, type - 4); 380143e05652SRichard Henderson } 380243e05652SRichard Henderson } else { 380343e05652SRichard Henderson dest &= -4; /* priv = 0 */ 380443e05652SRichard Henderson } 380543e05652SRichard Henderson #endif 380643e05652SRichard Henderson 38076e5f5300SSven Schnelle if (a->l) { 38086fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 38096e5f5300SSven Schnelle if (ctx->privilege < 3) { 38106fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 38116e5f5300SSven Schnelle } 38126fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 38136e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 38146e5f5300SSven Schnelle } 38156e5f5300SSven Schnelle 38166e5f5300SSven Schnelle return do_dbranch(ctx, dest, 0, a->n); 381743e05652SRichard Henderson } 381843e05652SRichard Henderson 38198340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 382098cd9ca7SRichard Henderson { 3821b35aec85SRichard Henderson if (a->x) { 3822aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 38236fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3); 38246fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8); 3825660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 38268340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3827b35aec85SRichard Henderson } else { 3828b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 3829b35aec85SRichard Henderson return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n); 3830b35aec85SRichard Henderson } 383198cd9ca7SRichard Henderson } 383298cd9ca7SRichard Henderson 38338340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 383498cd9ca7SRichard Henderson { 38356fd0c7bcSRichard Henderson TCGv_i64 dest; 383698cd9ca7SRichard Henderson 38378340f534SRichard Henderson if (a->x == 0) { 38388340f534SRichard Henderson dest = load_gpr(ctx, a->b); 383998cd9ca7SRichard Henderson } else { 3840aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 38416fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 38426fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 384398cd9ca7SRichard Henderson } 3844660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 38458340f534SRichard Henderson return do_ibranch(ctx, dest, 0, a->n); 384698cd9ca7SRichard Henderson } 384798cd9ca7SRichard Henderson 38488340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 384998cd9ca7SRichard Henderson { 38506fd0c7bcSRichard Henderson TCGv_i64 dest; 385198cd9ca7SRichard Henderson 3852c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 38538340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 38548340f534SRichard Henderson return do_ibranch(ctx, dest, a->l, a->n); 3855c301f34eSRichard Henderson #else 3856c301f34eSRichard Henderson nullify_over(ctx); 38578340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3858c301f34eSRichard Henderson 3859741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3860c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3861c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3862c301f34eSRichard Henderson } 3863741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest); 3864c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); 38658340f534SRichard Henderson if (a->l) { 3866741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var); 3867c301f34eSRichard Henderson } 38688340f534SRichard Henderson nullify_set(ctx, a->n); 3869c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 387031234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 387131234768SRichard Henderson return nullify_end(ctx); 3872c301f34eSRichard Henderson #endif 387398cd9ca7SRichard Henderson } 387498cd9ca7SRichard Henderson 3875a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 3876a8966ba7SRichard Henderson { 3877a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 3878a8966ba7SRichard Henderson return ctx->is_pa20; 3879a8966ba7SRichard Henderson } 3880a8966ba7SRichard Henderson 38811ca74648SRichard Henderson /* 38821ca74648SRichard Henderson * Float class 0 38831ca74648SRichard Henderson */ 3884ebe9383cSRichard Henderson 38851ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3886ebe9383cSRichard Henderson { 3887ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3888ebe9383cSRichard Henderson } 3889ebe9383cSRichard Henderson 389059f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 389159f8c04bSHelge Deller { 3892a300dad3SRichard Henderson uint64_t ret; 3893a300dad3SRichard Henderson 3894c53e401eSRichard Henderson if (ctx->is_pa20) { 3895a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 3896a300dad3SRichard Henderson } else { 3897a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 3898a300dad3SRichard Henderson } 3899a300dad3SRichard Henderson 390059f8c04bSHelge Deller nullify_over(ctx); 3901a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 390259f8c04bSHelge Deller return nullify_end(ctx); 390359f8c04bSHelge Deller } 390459f8c04bSHelge Deller 39051ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 39061ca74648SRichard Henderson { 39071ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 39081ca74648SRichard Henderson } 39091ca74648SRichard Henderson 3910ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3911ebe9383cSRichard Henderson { 3912ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 3913ebe9383cSRichard Henderson } 3914ebe9383cSRichard Henderson 39151ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 39161ca74648SRichard Henderson { 39171ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 39181ca74648SRichard Henderson } 39191ca74648SRichard Henderson 39201ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3921ebe9383cSRichard Henderson { 3922ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 3923ebe9383cSRichard Henderson } 3924ebe9383cSRichard Henderson 39251ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 39261ca74648SRichard Henderson { 39271ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 39281ca74648SRichard Henderson } 39291ca74648SRichard Henderson 3930ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3931ebe9383cSRichard Henderson { 3932ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 3933ebe9383cSRichard Henderson } 3934ebe9383cSRichard Henderson 39351ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 39361ca74648SRichard Henderson { 39371ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 39381ca74648SRichard Henderson } 39391ca74648SRichard Henderson 39401ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 39411ca74648SRichard Henderson { 39421ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 39431ca74648SRichard Henderson } 39441ca74648SRichard Henderson 39451ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 39461ca74648SRichard Henderson { 39471ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 39481ca74648SRichard Henderson } 39491ca74648SRichard Henderson 39501ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 39511ca74648SRichard Henderson { 39521ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 39531ca74648SRichard Henderson } 39541ca74648SRichard Henderson 39551ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 39561ca74648SRichard Henderson { 39571ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 39581ca74648SRichard Henderson } 39591ca74648SRichard Henderson 39601ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3961ebe9383cSRichard Henderson { 3962ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 3963ebe9383cSRichard Henderson } 3964ebe9383cSRichard Henderson 39651ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 39661ca74648SRichard Henderson { 39671ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 39681ca74648SRichard Henderson } 39691ca74648SRichard Henderson 3970ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3971ebe9383cSRichard Henderson { 3972ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 3973ebe9383cSRichard Henderson } 3974ebe9383cSRichard Henderson 39751ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 39761ca74648SRichard Henderson { 39771ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 39781ca74648SRichard Henderson } 39791ca74648SRichard Henderson 39801ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3981ebe9383cSRichard Henderson { 3982ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 3983ebe9383cSRichard Henderson } 3984ebe9383cSRichard Henderson 39851ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 39861ca74648SRichard Henderson { 39871ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 39881ca74648SRichard Henderson } 39891ca74648SRichard Henderson 3990ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3991ebe9383cSRichard Henderson { 3992ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 3993ebe9383cSRichard Henderson } 3994ebe9383cSRichard Henderson 39951ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 39961ca74648SRichard Henderson { 39971ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 39981ca74648SRichard Henderson } 39991ca74648SRichard Henderson 40001ca74648SRichard Henderson /* 40011ca74648SRichard Henderson * Float class 1 40021ca74648SRichard Henderson */ 40031ca74648SRichard Henderson 40041ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 40051ca74648SRichard Henderson { 40061ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 40071ca74648SRichard Henderson } 40081ca74648SRichard Henderson 40091ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 40101ca74648SRichard Henderson { 40111ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 40121ca74648SRichard Henderson } 40131ca74648SRichard Henderson 40141ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 40151ca74648SRichard Henderson { 40161ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 40171ca74648SRichard Henderson } 40181ca74648SRichard Henderson 40191ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 40201ca74648SRichard Henderson { 40211ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 40221ca74648SRichard Henderson } 40231ca74648SRichard Henderson 40241ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 40251ca74648SRichard Henderson { 40261ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 40271ca74648SRichard Henderson } 40281ca74648SRichard Henderson 40291ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 40301ca74648SRichard Henderson { 40311ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 40321ca74648SRichard Henderson } 40331ca74648SRichard Henderson 40341ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 40351ca74648SRichard Henderson { 40361ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 40371ca74648SRichard Henderson } 40381ca74648SRichard Henderson 40391ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 40401ca74648SRichard Henderson { 40411ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 40421ca74648SRichard Henderson } 40431ca74648SRichard Henderson 40441ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 40451ca74648SRichard Henderson { 40461ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 40471ca74648SRichard Henderson } 40481ca74648SRichard Henderson 40491ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 40501ca74648SRichard Henderson { 40511ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 40521ca74648SRichard Henderson } 40531ca74648SRichard Henderson 40541ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 40551ca74648SRichard Henderson { 40561ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 40571ca74648SRichard Henderson } 40581ca74648SRichard Henderson 40591ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 40601ca74648SRichard Henderson { 40611ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 40621ca74648SRichard Henderson } 40631ca74648SRichard Henderson 40641ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 40651ca74648SRichard Henderson { 40661ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 40671ca74648SRichard Henderson } 40681ca74648SRichard Henderson 40691ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 40701ca74648SRichard Henderson { 40711ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 40721ca74648SRichard Henderson } 40731ca74648SRichard Henderson 40741ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 40751ca74648SRichard Henderson { 40761ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 40771ca74648SRichard Henderson } 40781ca74648SRichard Henderson 40791ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 40801ca74648SRichard Henderson { 40811ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 40821ca74648SRichard Henderson } 40831ca74648SRichard Henderson 40841ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 40851ca74648SRichard Henderson { 40861ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 40871ca74648SRichard Henderson } 40881ca74648SRichard Henderson 40891ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 40901ca74648SRichard Henderson { 40911ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 40921ca74648SRichard Henderson } 40931ca74648SRichard Henderson 40941ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 40951ca74648SRichard Henderson { 40961ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 40971ca74648SRichard Henderson } 40981ca74648SRichard Henderson 40991ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 41001ca74648SRichard Henderson { 41011ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 41021ca74648SRichard Henderson } 41031ca74648SRichard Henderson 41041ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 41051ca74648SRichard Henderson { 41061ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 41071ca74648SRichard Henderson } 41081ca74648SRichard Henderson 41091ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 41101ca74648SRichard Henderson { 41111ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 41121ca74648SRichard Henderson } 41131ca74648SRichard Henderson 41141ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 41151ca74648SRichard Henderson { 41161ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 41171ca74648SRichard Henderson } 41181ca74648SRichard Henderson 41191ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 41201ca74648SRichard Henderson { 41211ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 41221ca74648SRichard Henderson } 41231ca74648SRichard Henderson 41241ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 41251ca74648SRichard Henderson { 41261ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 41271ca74648SRichard Henderson } 41281ca74648SRichard Henderson 41291ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 41301ca74648SRichard Henderson { 41311ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 41321ca74648SRichard Henderson } 41331ca74648SRichard Henderson 41341ca74648SRichard Henderson /* 41351ca74648SRichard Henderson * Float class 2 41361ca74648SRichard Henderson */ 41371ca74648SRichard Henderson 41381ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4139ebe9383cSRichard Henderson { 4140ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4141ebe9383cSRichard Henderson 4142ebe9383cSRichard Henderson nullify_over(ctx); 4143ebe9383cSRichard Henderson 41441ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 41451ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 414629dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 414729dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4148ebe9383cSRichard Henderson 4149ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4150ebe9383cSRichard Henderson 41511ca74648SRichard Henderson return nullify_end(ctx); 4152ebe9383cSRichard Henderson } 4153ebe9383cSRichard Henderson 41541ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4155ebe9383cSRichard Henderson { 4156ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4157ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4158ebe9383cSRichard Henderson 4159ebe9383cSRichard Henderson nullify_over(ctx); 4160ebe9383cSRichard Henderson 41611ca74648SRichard Henderson ta = load_frd0(a->r1); 41621ca74648SRichard Henderson tb = load_frd0(a->r2); 416329dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 416429dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4165ebe9383cSRichard Henderson 4166ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4167ebe9383cSRichard Henderson 416831234768SRichard Henderson return nullify_end(ctx); 4169ebe9383cSRichard Henderson } 4170ebe9383cSRichard Henderson 41711ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4172ebe9383cSRichard Henderson { 41736fd0c7bcSRichard Henderson TCGv_i64 t; 4174ebe9383cSRichard Henderson 4175ebe9383cSRichard Henderson nullify_over(ctx); 4176ebe9383cSRichard Henderson 4177aac0f603SRichard Henderson t = tcg_temp_new_i64(); 41786fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4179ebe9383cSRichard Henderson 41801ca74648SRichard Henderson if (a->y == 1) { 4181ebe9383cSRichard Henderson int mask; 4182ebe9383cSRichard Henderson bool inv = false; 4183ebe9383cSRichard Henderson 41841ca74648SRichard Henderson switch (a->c) { 4185ebe9383cSRichard Henderson case 0: /* simple */ 41866fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 4187ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4188ebe9383cSRichard Henderson goto done; 4189ebe9383cSRichard Henderson case 2: /* rej */ 4190ebe9383cSRichard Henderson inv = true; 4191ebe9383cSRichard Henderson /* fallthru */ 4192ebe9383cSRichard Henderson case 1: /* acc */ 4193ebe9383cSRichard Henderson mask = 0x43ff800; 4194ebe9383cSRichard Henderson break; 4195ebe9383cSRichard Henderson case 6: /* rej8 */ 4196ebe9383cSRichard Henderson inv = true; 4197ebe9383cSRichard Henderson /* fallthru */ 4198ebe9383cSRichard Henderson case 5: /* acc8 */ 4199ebe9383cSRichard Henderson mask = 0x43f8000; 4200ebe9383cSRichard Henderson break; 4201ebe9383cSRichard Henderson case 9: /* acc6 */ 4202ebe9383cSRichard Henderson mask = 0x43e0000; 4203ebe9383cSRichard Henderson break; 4204ebe9383cSRichard Henderson case 13: /* acc4 */ 4205ebe9383cSRichard Henderson mask = 0x4380000; 4206ebe9383cSRichard Henderson break; 4207ebe9383cSRichard Henderson case 17: /* acc2 */ 4208ebe9383cSRichard Henderson mask = 0x4200000; 4209ebe9383cSRichard Henderson break; 4210ebe9383cSRichard Henderson default: 42111ca74648SRichard Henderson gen_illegal(ctx); 42121ca74648SRichard Henderson return true; 4213ebe9383cSRichard Henderson } 4214ebe9383cSRichard Henderson if (inv) { 42156fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 42166fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 4217ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 4218ebe9383cSRichard Henderson } else { 42196fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 4220ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 4221ebe9383cSRichard Henderson } 42221ca74648SRichard Henderson } else { 42231ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 42241ca74648SRichard Henderson 42256fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 42261ca74648SRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 42271ca74648SRichard Henderson } 42281ca74648SRichard Henderson 4229ebe9383cSRichard Henderson done: 423031234768SRichard Henderson return nullify_end(ctx); 4231ebe9383cSRichard Henderson } 4232ebe9383cSRichard Henderson 42331ca74648SRichard Henderson /* 42341ca74648SRichard Henderson * Float class 2 42351ca74648SRichard Henderson */ 42361ca74648SRichard Henderson 42371ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4238ebe9383cSRichard Henderson { 42391ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 42401ca74648SRichard Henderson } 42411ca74648SRichard Henderson 42421ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 42431ca74648SRichard Henderson { 42441ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 42451ca74648SRichard Henderson } 42461ca74648SRichard Henderson 42471ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 42481ca74648SRichard Henderson { 42491ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 42501ca74648SRichard Henderson } 42511ca74648SRichard Henderson 42521ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 42531ca74648SRichard Henderson { 42541ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 42551ca74648SRichard Henderson } 42561ca74648SRichard Henderson 42571ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 42581ca74648SRichard Henderson { 42591ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 42601ca74648SRichard Henderson } 42611ca74648SRichard Henderson 42621ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 42631ca74648SRichard Henderson { 42641ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 42651ca74648SRichard Henderson } 42661ca74648SRichard Henderson 42671ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 42681ca74648SRichard Henderson { 42691ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 42701ca74648SRichard Henderson } 42711ca74648SRichard Henderson 42721ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 42731ca74648SRichard Henderson { 42741ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 42751ca74648SRichard Henderson } 42761ca74648SRichard Henderson 42771ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 42781ca74648SRichard Henderson { 42791ca74648SRichard Henderson TCGv_i64 x, y; 4280ebe9383cSRichard Henderson 4281ebe9383cSRichard Henderson nullify_over(ctx); 4282ebe9383cSRichard Henderson 42831ca74648SRichard Henderson x = load_frw0_i64(a->r1); 42841ca74648SRichard Henderson y = load_frw0_i64(a->r2); 42851ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 42861ca74648SRichard Henderson save_frd(a->t, x); 4287ebe9383cSRichard Henderson 428831234768SRichard Henderson return nullify_end(ctx); 4289ebe9383cSRichard Henderson } 4290ebe9383cSRichard Henderson 4291ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4292ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4293ebe9383cSRichard Henderson { 4294ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4295ebe9383cSRichard Henderson } 4296ebe9383cSRichard Henderson 4297b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4298ebe9383cSRichard Henderson { 4299b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4300b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4301b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4302b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4303b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4304ebe9383cSRichard Henderson 4305ebe9383cSRichard Henderson nullify_over(ctx); 4306ebe9383cSRichard Henderson 4307ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4308ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4309ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4310ebe9383cSRichard Henderson 431131234768SRichard Henderson return nullify_end(ctx); 4312ebe9383cSRichard Henderson } 4313ebe9383cSRichard Henderson 4314b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4315b1e2af57SRichard Henderson { 4316b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4317b1e2af57SRichard Henderson } 4318b1e2af57SRichard Henderson 4319b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4320b1e2af57SRichard Henderson { 4321b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4322b1e2af57SRichard Henderson } 4323b1e2af57SRichard Henderson 4324b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4325b1e2af57SRichard Henderson { 4326b1e2af57SRichard Henderson nullify_over(ctx); 4327b1e2af57SRichard Henderson 4328b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4329b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4330b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4331b1e2af57SRichard Henderson 4332b1e2af57SRichard Henderson return nullify_end(ctx); 4333b1e2af57SRichard Henderson } 4334b1e2af57SRichard Henderson 4335b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4336b1e2af57SRichard Henderson { 4337b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4338b1e2af57SRichard Henderson } 4339b1e2af57SRichard Henderson 4340b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4341b1e2af57SRichard Henderson { 4342b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4343b1e2af57SRichard Henderson } 4344b1e2af57SRichard Henderson 4345c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4346ebe9383cSRichard Henderson { 4347c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4348ebe9383cSRichard Henderson 4349ebe9383cSRichard Henderson nullify_over(ctx); 4350c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4351c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4352c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4353ebe9383cSRichard Henderson 4354c3bad4f8SRichard Henderson if (a->neg) { 4355ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4356ebe9383cSRichard Henderson } else { 4357ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4358ebe9383cSRichard Henderson } 4359ebe9383cSRichard Henderson 4360c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 436131234768SRichard Henderson return nullify_end(ctx); 4362ebe9383cSRichard Henderson } 4363ebe9383cSRichard Henderson 4364c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4365ebe9383cSRichard Henderson { 4366c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4367ebe9383cSRichard Henderson 4368ebe9383cSRichard Henderson nullify_over(ctx); 4369c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4370c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4371c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4372ebe9383cSRichard Henderson 4373c3bad4f8SRichard Henderson if (a->neg) { 4374ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4375ebe9383cSRichard Henderson } else { 4376ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4377ebe9383cSRichard Henderson } 4378ebe9383cSRichard Henderson 4379c3bad4f8SRichard Henderson save_frd(a->t, x); 438031234768SRichard Henderson return nullify_end(ctx); 4381ebe9383cSRichard Henderson } 4382ebe9383cSRichard Henderson 438315da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a) 438415da177bSSven Schnelle { 4385cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4386cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4387cf6b28d4SHelge Deller if (a->i == 0x100) { 4388cf6b28d4SHelge Deller /* emulate PDC BTLB, called by SeaBIOS-hppa */ 4389ad75a51eSRichard Henderson nullify_over(ctx); 4390ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4391cf6b28d4SHelge Deller return nullify_end(ctx); 439215da177bSSven Schnelle } 4393ad75a51eSRichard Henderson #endif 4394ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4395ad75a51eSRichard Henderson return true; 4396ad75a51eSRichard Henderson } 439715da177bSSven Schnelle 4398b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 439961766fe9SRichard Henderson { 440051b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4401f764718dSRichard Henderson int bound; 440261766fe9SRichard Henderson 440351b061fbSRichard Henderson ctx->cs = cs; 4404494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4405bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 44063d68ee7bSRichard Henderson 44073d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4408c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 44093d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 4410c01e5dfbSHelge Deller ctx->iaoq_f = ctx->base.pc_first | ctx->privilege; 4411c01e5dfbSHelge Deller ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege; 4412217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4413c301f34eSRichard Henderson #else 4414494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4415bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4416bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4417bb67ec32SRichard Henderson : MMU_PHYS_IDX); 44183d68ee7bSRichard Henderson 4419c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4420c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4421c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4422c301f34eSRichard Henderson int32_t diff = cs_base; 4423c301f34eSRichard Henderson 4424c301f34eSRichard Henderson ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4425c301f34eSRichard Henderson ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); 4426c301f34eSRichard Henderson #endif 442751b061fbSRichard Henderson ctx->iaoq_n = -1; 4428f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 442961766fe9SRichard Henderson 4430a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4431a4db4a78SRichard Henderson 44323d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 44333d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4434b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 443561766fe9SRichard Henderson } 443661766fe9SRichard Henderson 443751b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 443851b061fbSRichard Henderson { 443951b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 444061766fe9SRichard Henderson 44413d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 444251b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 444351b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4444494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 444551b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 444651b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4447129e9cc3SRichard Henderson } 444851b061fbSRichard Henderson ctx->null_lab = NULL; 444961766fe9SRichard Henderson } 445061766fe9SRichard Henderson 445151b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 445251b061fbSRichard Henderson { 445351b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 445451b061fbSRichard Henderson 445551b061fbSRichard Henderson tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b); 445651b061fbSRichard Henderson } 445751b061fbSRichard Henderson 445851b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 445951b061fbSRichard Henderson { 446051b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4461b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 446251b061fbSRichard Henderson DisasJumpType ret; 446351b061fbSRichard Henderson 446451b061fbSRichard Henderson /* Execute one insn. */ 4465ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4466c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 446731234768SRichard Henderson do_page_zero(ctx); 446831234768SRichard Henderson ret = ctx->base.is_jmp; 4469869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4470ba1d0b44SRichard Henderson } else 4471ba1d0b44SRichard Henderson #endif 4472ba1d0b44SRichard Henderson { 447361766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 447461766fe9SRichard Henderson the page permissions for execute. */ 44754e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 447661766fe9SRichard Henderson 447761766fe9SRichard Henderson /* Set up the IA queue for the next insn. 447861766fe9SRichard Henderson This will be overwritten by a branch. */ 447951b061fbSRichard Henderson if (ctx->iaoq_b == -1) { 448051b061fbSRichard Henderson ctx->iaoq_n = -1; 4481aac0f603SRichard Henderson ctx->iaoq_n_var = tcg_temp_new_i64(); 44826fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 448361766fe9SRichard Henderson } else { 448451b061fbSRichard Henderson ctx->iaoq_n = ctx->iaoq_b + 4; 4485f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 448661766fe9SRichard Henderson } 448761766fe9SRichard Henderson 448851b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 448951b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4490869051eaSRichard Henderson ret = DISAS_NEXT; 4491129e9cc3SRichard Henderson } else { 44921a19da0dSRichard Henderson ctx->insn = insn; 449331274b46SRichard Henderson if (!decode(ctx, insn)) { 449431274b46SRichard Henderson gen_illegal(ctx); 449531274b46SRichard Henderson } 449631234768SRichard Henderson ret = ctx->base.is_jmp; 449751b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4498129e9cc3SRichard Henderson } 449961766fe9SRichard Henderson } 450061766fe9SRichard Henderson 45013d68ee7bSRichard Henderson /* Advance the insn queue. Note that this check also detects 45023d68ee7bSRichard Henderson a priority change within the instruction queue. */ 450351b061fbSRichard Henderson if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 4504c301f34eSRichard Henderson if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 4505c301f34eSRichard Henderson && use_goto_tb(ctx, ctx->iaoq_b) 4506c301f34eSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4507c301f34eSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 450851b061fbSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 450951b061fbSRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 451031234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_NORETURN; 4511129e9cc3SRichard Henderson } else { 451231234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE; 451361766fe9SRichard Henderson } 4514129e9cc3SRichard Henderson } 451551b061fbSRichard Henderson ctx->iaoq_f = ctx->iaoq_b; 451651b061fbSRichard Henderson ctx->iaoq_b = ctx->iaoq_n; 4517c301f34eSRichard Henderson ctx->base.pc_next += 4; 451861766fe9SRichard Henderson 4519c5d0aec2SRichard Henderson switch (ret) { 4520c5d0aec2SRichard Henderson case DISAS_NORETURN: 4521c5d0aec2SRichard Henderson case DISAS_IAQ_N_UPDATED: 4522c5d0aec2SRichard Henderson break; 4523c5d0aec2SRichard Henderson 4524c5d0aec2SRichard Henderson case DISAS_NEXT: 4525c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE: 4526c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 452751b061fbSRichard Henderson if (ctx->iaoq_f == -1) { 4528a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b); 4529741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 4530c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY 4531c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 4532c301f34eSRichard Henderson #endif 453351b061fbSRichard Henderson nullify_save(ctx); 4534c5d0aec2SRichard Henderson ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT 4535c5d0aec2SRichard Henderson ? DISAS_EXIT 4536c5d0aec2SRichard Henderson : DISAS_IAQ_N_UPDATED); 453751b061fbSRichard Henderson } else if (ctx->iaoq_b == -1) { 4538a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var); 453961766fe9SRichard Henderson } 4540c5d0aec2SRichard Henderson break; 4541c5d0aec2SRichard Henderson 4542c5d0aec2SRichard Henderson default: 4543c5d0aec2SRichard Henderson g_assert_not_reached(); 4544c5d0aec2SRichard Henderson } 454561766fe9SRichard Henderson } 454661766fe9SRichard Henderson 454751b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 454851b061fbSRichard Henderson { 454951b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4550e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 455151b061fbSRichard Henderson 4552e1b5a5edSRichard Henderson switch (is_jmp) { 4553869051eaSRichard Henderson case DISAS_NORETURN: 455461766fe9SRichard Henderson break; 455551b061fbSRichard Henderson case DISAS_TOO_MANY: 4556869051eaSRichard Henderson case DISAS_IAQ_N_STALE: 4557e1b5a5edSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4558741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 4559741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 456051b061fbSRichard Henderson nullify_save(ctx); 456161766fe9SRichard Henderson /* FALLTHRU */ 4562869051eaSRichard Henderson case DISAS_IAQ_N_UPDATED: 45638532a14eSRichard Henderson if (is_jmp != DISAS_IAQ_N_STALE_EXIT) { 45647f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 45658532a14eSRichard Henderson break; 456661766fe9SRichard Henderson } 4567c5d0aec2SRichard Henderson /* FALLTHRU */ 4568c5d0aec2SRichard Henderson case DISAS_EXIT: 4569c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 457061766fe9SRichard Henderson break; 457161766fe9SRichard Henderson default: 457251b061fbSRichard Henderson g_assert_not_reached(); 457361766fe9SRichard Henderson } 457451b061fbSRichard Henderson } 457561766fe9SRichard Henderson 45768eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 45778eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 457851b061fbSRichard Henderson { 4579c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 458061766fe9SRichard Henderson 4581ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4582ba1d0b44SRichard Henderson switch (pc) { 45837ad439dfSRichard Henderson case 0x00: 45848eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4585ba1d0b44SRichard Henderson return; 45867ad439dfSRichard Henderson case 0xb0: 45878eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4588ba1d0b44SRichard Henderson return; 45897ad439dfSRichard Henderson case 0xe0: 45908eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4591ba1d0b44SRichard Henderson return; 45927ad439dfSRichard Henderson case 0x100: 45938eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4594ba1d0b44SRichard Henderson return; 45957ad439dfSRichard Henderson } 4596ba1d0b44SRichard Henderson #endif 4597ba1d0b44SRichard Henderson 45988eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 45998eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 460061766fe9SRichard Henderson } 460151b061fbSRichard Henderson 460251b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 460351b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 460451b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 460551b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 460651b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 460751b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 460851b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 460951b061fbSRichard Henderson }; 461051b061fbSRichard Henderson 4611597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 4612306c8721SRichard Henderson target_ulong pc, void *host_pc) 461351b061fbSRichard Henderson { 461451b061fbSRichard Henderson DisasContext ctx; 4615306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 461661766fe9SRichard Henderson } 4617