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; 47*f5b5c857SRichard Henderson TCGOp *insn_start; 4861766fe9SRichard Henderson 49c53e401eSRichard Henderson uint64_t iaoq_f; 50c53e401eSRichard Henderson uint64_t iaoq_b; 51c53e401eSRichard Henderson uint64_t iaoq_n; 526fd0c7bcSRichard Henderson TCGv_i64 iaoq_n_var; 5361766fe9SRichard Henderson 5461766fe9SRichard Henderson DisasCond null_cond; 5561766fe9SRichard Henderson TCGLabel *null_lab; 5661766fe9SRichard Henderson 57a4db4a78SRichard Henderson TCGv_i64 zero; 58a4db4a78SRichard Henderson 591a19da0dSRichard Henderson uint32_t insn; 60494737b7SRichard Henderson uint32_t tb_flags; 613d68ee7bSRichard Henderson int mmu_idx; 623d68ee7bSRichard Henderson int privilege; 6361766fe9SRichard Henderson bool psw_n_nonzero; 64bd6243a3SRichard Henderson bool is_pa20; 65217d1a5eSRichard Henderson 66217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 67217d1a5eSRichard Henderson MemOp unalign; 68217d1a5eSRichard Henderson #endif 6961766fe9SRichard Henderson } DisasContext; 7061766fe9SRichard Henderson 71217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 72217d1a5eSRichard Henderson #define UNALIGN(C) (C)->unalign 73217d1a5eSRichard Henderson #else 742d4afb03SRichard Henderson #define UNALIGN(C) MO_ALIGN 75217d1a5eSRichard Henderson #endif 76217d1a5eSRichard Henderson 77e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 78451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val) 79e36f27efSRichard Henderson { 80e36f27efSRichard Henderson if (val & PSW_SM_E) { 81e36f27efSRichard Henderson val = (val & ~PSW_SM_E) | PSW_E; 82e36f27efSRichard Henderson } 83e36f27efSRichard Henderson if (val & PSW_SM_W) { 84e36f27efSRichard Henderson val = (val & ~PSW_SM_W) | PSW_W; 85e36f27efSRichard Henderson } 86e36f27efSRichard Henderson return val; 87e36f27efSRichard Henderson } 88e36f27efSRichard Henderson 89deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base. */ 90451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val) 91deee69a1SRichard Henderson { 92deee69a1SRichard Henderson return ~val; 93deee69a1SRichard Henderson } 94deee69a1SRichard Henderson 951cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value 961cd012a5SRichard Henderson we use for the final M. */ 97451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val) 981cd012a5SRichard Henderson { 991cd012a5SRichard Henderson return val & 2 ? (val & 1 ? -1 : 1) : 0; 1001cd012a5SRichard Henderson } 1011cd012a5SRichard Henderson 102740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify. */ 103451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val) 104740038d7SRichard Henderson { 105740038d7SRichard Henderson return val ? 1 : -1; 106740038d7SRichard Henderson } 107740038d7SRichard Henderson 108451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val) 109740038d7SRichard Henderson { 110740038d7SRichard Henderson return val ? -1 : 1; 111740038d7SRichard Henderson } 112740038d7SRichard Henderson 113740038d7SRichard Henderson /* Used for branch targets and fp memory ops. */ 114451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val) 11501afb7beSRichard Henderson { 11601afb7beSRichard Henderson return val << 2; 11701afb7beSRichard Henderson } 11801afb7beSRichard Henderson 119740038d7SRichard Henderson /* Used for fp memory ops. */ 120451e4ffdSRichard Henderson static int expand_shl3(DisasContext *ctx, int val) 121740038d7SRichard Henderson { 122740038d7SRichard Henderson return val << 3; 123740038d7SRichard Henderson } 124740038d7SRichard Henderson 1250588e061SRichard Henderson /* Used for assemble_21. */ 126451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val) 1270588e061SRichard Henderson { 1280588e061SRichard Henderson return val << 11; 1290588e061SRichard Henderson } 1300588e061SRichard Henderson 13172ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val) 13272ae4f2bSRichard Henderson { 13372ae4f2bSRichard Henderson /* 13472ae4f2bSRichard Henderson * Officially, 32 * x + 32 - y. 13572ae4f2bSRichard Henderson * Here, x is already in bit 5, and y is [4:0]. 13672ae4f2bSRichard Henderson * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1, 13772ae4f2bSRichard Henderson * with the overflow from bit 4 summing with x. 13872ae4f2bSRichard Henderson */ 13972ae4f2bSRichard Henderson return (val ^ 31) + 1; 14072ae4f2bSRichard Henderson } 14172ae4f2bSRichard Henderson 142c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */ 143c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val) 144c65c3ee1SRichard Henderson { 145c65c3ee1SRichard Henderson return val ? val : 4; /* 0 == "*<<" */ 146c65c3ee1SRichard Henderson } 147c65c3ee1SRichard Henderson 14801afb7beSRichard Henderson 14940f9f908SRichard Henderson /* Include the auto-generated decoder. */ 150abff1abfSPaolo Bonzini #include "decode-insns.c.inc" 15140f9f908SRichard Henderson 15261766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 15361766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 154869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 15561766fe9SRichard Henderson 15661766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 15761766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 158869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 15961766fe9SRichard Henderson 160e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 161e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 162e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 163c5d0aec2SRichard Henderson #define DISAS_EXIT DISAS_TARGET_3 164e1b5a5edSRichard Henderson 16561766fe9SRichard Henderson /* global register indexes */ 1666fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32]; 16733423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 168494737b7SRichard Henderson static TCGv_i64 cpu_srH; 1696fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f; 1706fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b; 171c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 172c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 1736fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar; 1746fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n; 1756fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v; 1766fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb; 1776fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb; 17861766fe9SRichard Henderson 17961766fe9SRichard Henderson void hppa_translate_init(void) 18061766fe9SRichard Henderson { 18161766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 18261766fe9SRichard Henderson 1836fd0c7bcSRichard Henderson typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 18461766fe9SRichard Henderson static const GlobalVar vars[] = { 18535136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 18661766fe9SRichard Henderson DEF_VAR(psw_n), 18761766fe9SRichard Henderson DEF_VAR(psw_v), 18861766fe9SRichard Henderson DEF_VAR(psw_cb), 18961766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 19061766fe9SRichard Henderson DEF_VAR(iaoq_f), 19161766fe9SRichard Henderson DEF_VAR(iaoq_b), 19261766fe9SRichard Henderson }; 19361766fe9SRichard Henderson 19461766fe9SRichard Henderson #undef DEF_VAR 19561766fe9SRichard Henderson 19661766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 19761766fe9SRichard Henderson static const char gr_names[32][4] = { 19861766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 19961766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 20061766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 20161766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 20261766fe9SRichard Henderson }; 20333423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 204494737b7SRichard Henderson static const char sr_names[5][4] = { 205494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 20633423472SRichard Henderson }; 20761766fe9SRichard Henderson 20861766fe9SRichard Henderson int i; 20961766fe9SRichard Henderson 210f764718dSRichard Henderson cpu_gr[0] = NULL; 21161766fe9SRichard Henderson for (i = 1; i < 32; i++) { 212ad75a51eSRichard Henderson cpu_gr[i] = tcg_global_mem_new(tcg_env, 21361766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 21461766fe9SRichard Henderson gr_names[i]); 21561766fe9SRichard Henderson } 21633423472SRichard Henderson for (i = 0; i < 4; i++) { 217ad75a51eSRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 21833423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 21933423472SRichard Henderson sr_names[i]); 22033423472SRichard Henderson } 221ad75a51eSRichard Henderson cpu_srH = tcg_global_mem_new_i64(tcg_env, 222494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 223494737b7SRichard Henderson sr_names[4]); 22461766fe9SRichard Henderson 22561766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 22661766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 227ad75a51eSRichard Henderson *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 22861766fe9SRichard Henderson } 229c301f34eSRichard Henderson 230ad75a51eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 231c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 232c301f34eSRichard Henderson "iasq_f"); 233ad75a51eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 234c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 235c301f34eSRichard Henderson "iasq_b"); 23661766fe9SRichard Henderson } 23761766fe9SRichard Henderson 238*f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg) 239*f5b5c857SRichard Henderson { 240*f5b5c857SRichard Henderson assert(ctx->insn_start != NULL); 241*f5b5c857SRichard Henderson tcg_set_insn_start_param(ctx->insn_start, 2, breg); 242*f5b5c857SRichard Henderson ctx->insn_start = NULL; 243*f5b5c857SRichard Henderson } 244*f5b5c857SRichard Henderson 245129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 246129e9cc3SRichard Henderson { 247f764718dSRichard Henderson return (DisasCond){ 248f764718dSRichard Henderson .c = TCG_COND_NEVER, 249f764718dSRichard Henderson .a0 = NULL, 250f764718dSRichard Henderson .a1 = NULL, 251f764718dSRichard Henderson }; 252129e9cc3SRichard Henderson } 253129e9cc3SRichard Henderson 254df0232feSRichard Henderson static DisasCond cond_make_t(void) 255df0232feSRichard Henderson { 256df0232feSRichard Henderson return (DisasCond){ 257df0232feSRichard Henderson .c = TCG_COND_ALWAYS, 258df0232feSRichard Henderson .a0 = NULL, 259df0232feSRichard Henderson .a1 = NULL, 260df0232feSRichard Henderson }; 261df0232feSRichard Henderson } 262df0232feSRichard Henderson 263129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 264129e9cc3SRichard Henderson { 265f764718dSRichard Henderson return (DisasCond){ 266f764718dSRichard Henderson .c = TCG_COND_NE, 267f764718dSRichard Henderson .a0 = cpu_psw_n, 2686fd0c7bcSRichard Henderson .a1 = tcg_constant_i64(0) 269f764718dSRichard Henderson }; 270129e9cc3SRichard Henderson } 271129e9cc3SRichard Henderson 2726fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 273b47a4a02SSven Schnelle { 274b47a4a02SSven Schnelle assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 2754fe9533aSRichard Henderson return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 2764fe9533aSRichard Henderson } 2774fe9533aSRichard Henderson 2786fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0) 2794fe9533aSRichard Henderson { 2806fd0c7bcSRichard Henderson return cond_make_tmp(c, a0, tcg_constant_i64(0)); 281b47a4a02SSven Schnelle } 282b47a4a02SSven Schnelle 2836fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0) 284129e9cc3SRichard Henderson { 285aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2866fd0c7bcSRichard Henderson tcg_gen_mov_i64(tmp, a0); 287b47a4a02SSven Schnelle return cond_make_0_tmp(c, tmp); 288129e9cc3SRichard Henderson } 289129e9cc3SRichard Henderson 2906fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 291129e9cc3SRichard Henderson { 292aac0f603SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 293aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 294129e9cc3SRichard Henderson 2956fd0c7bcSRichard Henderson tcg_gen_mov_i64(t0, a0); 2966fd0c7bcSRichard Henderson tcg_gen_mov_i64(t1, a1); 2974fe9533aSRichard Henderson return cond_make_tmp(c, t0, t1); 298129e9cc3SRichard Henderson } 299129e9cc3SRichard Henderson 300129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 301129e9cc3SRichard Henderson { 302129e9cc3SRichard Henderson switch (cond->c) { 303129e9cc3SRichard Henderson default: 304f764718dSRichard Henderson cond->a0 = NULL; 305f764718dSRichard Henderson cond->a1 = NULL; 306129e9cc3SRichard Henderson /* fallthru */ 307129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 308129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 309129e9cc3SRichard Henderson break; 310129e9cc3SRichard Henderson case TCG_COND_NEVER: 311129e9cc3SRichard Henderson break; 312129e9cc3SRichard Henderson } 313129e9cc3SRichard Henderson } 314129e9cc3SRichard Henderson 3156fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 31661766fe9SRichard Henderson { 31761766fe9SRichard Henderson if (reg == 0) { 318bc3da3cfSRichard Henderson return ctx->zero; 31961766fe9SRichard Henderson } else { 32061766fe9SRichard Henderson return cpu_gr[reg]; 32161766fe9SRichard Henderson } 32261766fe9SRichard Henderson } 32361766fe9SRichard Henderson 3246fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 32561766fe9SRichard Henderson { 326129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 327aac0f603SRichard Henderson return tcg_temp_new_i64(); 32861766fe9SRichard Henderson } else { 32961766fe9SRichard Henderson return cpu_gr[reg]; 33061766fe9SRichard Henderson } 33161766fe9SRichard Henderson } 33261766fe9SRichard Henderson 3336fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 334129e9cc3SRichard Henderson { 335129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 3366fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 337129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 338129e9cc3SRichard Henderson } else { 3396fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 340129e9cc3SRichard Henderson } 341129e9cc3SRichard Henderson } 342129e9cc3SRichard Henderson 3436fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 344129e9cc3SRichard Henderson { 345129e9cc3SRichard Henderson if (reg != 0) { 346129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 347129e9cc3SRichard Henderson } 348129e9cc3SRichard Henderson } 349129e9cc3SRichard Henderson 350e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 35196d6407fSRichard Henderson # define HI_OFS 0 35296d6407fSRichard Henderson # define LO_OFS 4 35396d6407fSRichard Henderson #else 35496d6407fSRichard Henderson # define HI_OFS 4 35596d6407fSRichard Henderson # define LO_OFS 0 35696d6407fSRichard Henderson #endif 35796d6407fSRichard Henderson 35896d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 35996d6407fSRichard Henderson { 36096d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 361ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 36296d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 36396d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 36496d6407fSRichard Henderson return ret; 36596d6407fSRichard Henderson } 36696d6407fSRichard Henderson 367ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 368ebe9383cSRichard Henderson { 369ebe9383cSRichard Henderson if (rt == 0) { 3700992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 3710992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 3720992a930SRichard Henderson return ret; 373ebe9383cSRichard Henderson } else { 374ebe9383cSRichard Henderson return load_frw_i32(rt); 375ebe9383cSRichard Henderson } 376ebe9383cSRichard Henderson } 377ebe9383cSRichard Henderson 378ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 379ebe9383cSRichard Henderson { 380ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 3810992a930SRichard Henderson if (rt == 0) { 3820992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 3830992a930SRichard Henderson } else { 384ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 385ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 386ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 387ebe9383cSRichard Henderson } 3880992a930SRichard Henderson return ret; 389ebe9383cSRichard Henderson } 390ebe9383cSRichard Henderson 39196d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 39296d6407fSRichard Henderson { 393ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 39496d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 39596d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 39696d6407fSRichard Henderson } 39796d6407fSRichard Henderson 39896d6407fSRichard Henderson #undef HI_OFS 39996d6407fSRichard Henderson #undef LO_OFS 40096d6407fSRichard Henderson 40196d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 40296d6407fSRichard Henderson { 40396d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 404ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 40596d6407fSRichard Henderson return ret; 40696d6407fSRichard Henderson } 40796d6407fSRichard Henderson 408ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 409ebe9383cSRichard Henderson { 410ebe9383cSRichard Henderson if (rt == 0) { 4110992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4120992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4130992a930SRichard Henderson return ret; 414ebe9383cSRichard Henderson } else { 415ebe9383cSRichard Henderson return load_frd(rt); 416ebe9383cSRichard Henderson } 417ebe9383cSRichard Henderson } 418ebe9383cSRichard Henderson 41996d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 42096d6407fSRichard Henderson { 421ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 42296d6407fSRichard Henderson } 42396d6407fSRichard Henderson 42433423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 42533423472SRichard Henderson { 42633423472SRichard Henderson #ifdef CONFIG_USER_ONLY 42733423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 42833423472SRichard Henderson #else 42933423472SRichard Henderson if (reg < 4) { 43033423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 431494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 432494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 43333423472SRichard Henderson } else { 434ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 43533423472SRichard Henderson } 43633423472SRichard Henderson #endif 43733423472SRichard Henderson } 43833423472SRichard Henderson 439129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 440129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 441129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 442129e9cc3SRichard Henderson { 443129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 444129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 445129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 446129e9cc3SRichard Henderson 447129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 448129e9cc3SRichard Henderson 449129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 4506e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 451aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 4526fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 453129e9cc3SRichard Henderson } 454129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 455129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 456129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 457129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 458129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 4596fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 460129e9cc3SRichard Henderson } 461129e9cc3SRichard Henderson 4626fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 463129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 464129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 465129e9cc3SRichard Henderson } 466129e9cc3SRichard Henderson } 467129e9cc3SRichard Henderson 468129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 469129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 470129e9cc3SRichard Henderson { 471129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 472129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 4736fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 474129e9cc3SRichard Henderson } 475129e9cc3SRichard Henderson return; 476129e9cc3SRichard Henderson } 4776e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 4786fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 479129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 480129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 481129e9cc3SRichard Henderson } 482129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 483129e9cc3SRichard Henderson } 484129e9cc3SRichard Henderson 485129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 486129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 487129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 488129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 489129e9cc3SRichard Henderson { 490129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 4916fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 492129e9cc3SRichard Henderson } 493129e9cc3SRichard Henderson } 494129e9cc3SRichard Henderson 495129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 49640f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 49740f9f908SRichard Henderson it may be tail-called from a translate function. */ 49831234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 499129e9cc3SRichard Henderson { 500129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 50131234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 502129e9cc3SRichard Henderson 503f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 504f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 505f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 506f49b3537SRichard Henderson 507129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 508129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 509129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 510129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 51131234768SRichard Henderson return true; 512129e9cc3SRichard Henderson } 513129e9cc3SRichard Henderson ctx->null_lab = NULL; 514129e9cc3SRichard Henderson 515129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 516129e9cc3SRichard Henderson /* The next instruction will be unconditional, 517129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 518129e9cc3SRichard Henderson gen_set_label(null_lab); 519129e9cc3SRichard Henderson } else { 520129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 521129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 522129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 523129e9cc3SRichard Henderson label we have the proper value in place. */ 524129e9cc3SRichard Henderson nullify_save(ctx); 525129e9cc3SRichard Henderson gen_set_label(null_lab); 526129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 527129e9cc3SRichard Henderson } 528869051eaSRichard Henderson if (status == DISAS_NORETURN) { 52931234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 530129e9cc3SRichard Henderson } 53131234768SRichard Henderson return true; 532129e9cc3SRichard Henderson } 533129e9cc3SRichard Henderson 534c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx) 535698240d1SRichard Henderson { 536698240d1SRichard Henderson return (ctx->tb_flags & PSW_W 537698240d1SRichard Henderson ? MAKE_64BIT_MASK(0, 62) 538698240d1SRichard Henderson : MAKE_64BIT_MASK(0, 32)); 539698240d1SRichard Henderson } 540698240d1SRichard Henderson 5416fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 5426fd0c7bcSRichard Henderson uint64_t ival, TCGv_i64 vval) 54361766fe9SRichard Henderson { 544c53e401eSRichard Henderson uint64_t mask = gva_offset_mask(ctx); 545f13bf343SRichard Henderson 546f13bf343SRichard Henderson if (ival != -1) { 5476fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, ival & mask); 548f13bf343SRichard Henderson return; 549f13bf343SRichard Henderson } 550f13bf343SRichard Henderson tcg_debug_assert(vval != NULL); 551f13bf343SRichard Henderson 552f13bf343SRichard Henderson /* 553f13bf343SRichard Henderson * We know that the IAOQ is already properly masked. 554f13bf343SRichard Henderson * This optimization is primarily for "iaoq_f = iaoq_b". 555f13bf343SRichard Henderson */ 556f13bf343SRichard Henderson if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) { 5576fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, vval); 55861766fe9SRichard Henderson } else { 5596fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, vval, mask); 56061766fe9SRichard Henderson } 56161766fe9SRichard Henderson } 56261766fe9SRichard Henderson 563c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp) 56461766fe9SRichard Henderson { 56561766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 56661766fe9SRichard Henderson } 56761766fe9SRichard Henderson 56861766fe9SRichard Henderson static void gen_excp_1(int exception) 56961766fe9SRichard Henderson { 570ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 57161766fe9SRichard Henderson } 57261766fe9SRichard Henderson 57331234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 57461766fe9SRichard Henderson { 575741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 576741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 577129e9cc3SRichard Henderson nullify_save(ctx); 57861766fe9SRichard Henderson gen_excp_1(exception); 57931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 58061766fe9SRichard Henderson } 58161766fe9SRichard Henderson 58231234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 5831a19da0dSRichard Henderson { 58431234768SRichard Henderson nullify_over(ctx); 5856fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 586ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 58731234768SRichard Henderson gen_excp(ctx, exc); 58831234768SRichard Henderson return nullify_end(ctx); 5891a19da0dSRichard Henderson } 5901a19da0dSRichard Henderson 59131234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 59261766fe9SRichard Henderson { 59331234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 59461766fe9SRichard Henderson } 59561766fe9SRichard Henderson 59640f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 59740f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 59840f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 59940f9f908SRichard Henderson #else 600e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 601e1b5a5edSRichard Henderson do { \ 602e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 60331234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 604e1b5a5edSRichard Henderson } \ 605e1b5a5edSRichard Henderson } while (0) 60640f9f908SRichard Henderson #endif 607e1b5a5edSRichard Henderson 608c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest) 60961766fe9SRichard Henderson { 61057f91498SRichard Henderson return translator_use_goto_tb(&ctx->base, dest); 61161766fe9SRichard Henderson } 61261766fe9SRichard Henderson 613129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 614129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 615129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 616129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 617129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 618129e9cc3SRichard Henderson { 619129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 620129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 621129e9cc3SRichard Henderson } 622129e9cc3SRichard Henderson 62361766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 624c53e401eSRichard Henderson uint64_t f, uint64_t b) 62561766fe9SRichard Henderson { 62661766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 62761766fe9SRichard Henderson tcg_gen_goto_tb(which); 628a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL); 629a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL); 63007ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 63161766fe9SRichard Henderson } else { 632741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b); 633741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var); 6347f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 63561766fe9SRichard Henderson } 63661766fe9SRichard Henderson } 63761766fe9SRichard Henderson 638b47a4a02SSven Schnelle static bool cond_need_sv(int c) 639b47a4a02SSven Schnelle { 640b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 641b47a4a02SSven Schnelle } 642b47a4a02SSven Schnelle 643b47a4a02SSven Schnelle static bool cond_need_cb(int c) 644b47a4a02SSven Schnelle { 645b47a4a02SSven Schnelle return c == 4 || c == 5; 646b47a4a02SSven Schnelle } 647b47a4a02SSven Schnelle 6486fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */ 64972ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d) 65072ca8753SRichard Henderson { 651c53e401eSRichard Henderson return !(ctx->is_pa20 && d); 65272ca8753SRichard Henderson } 65372ca8753SRichard Henderson 654b47a4a02SSven Schnelle /* 655b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 656b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 657b47a4a02SSven Schnelle */ 658b2167459SRichard Henderson 659a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 6606fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv) 661b2167459SRichard Henderson { 662b2167459SRichard Henderson DisasCond cond; 6636fd0c7bcSRichard Henderson TCGv_i64 tmp; 664b2167459SRichard Henderson 665b2167459SRichard Henderson switch (cf >> 1) { 666b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 667b2167459SRichard Henderson cond = cond_make_f(); 668b2167459SRichard Henderson break; 669b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 670a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 671aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6726fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 673a751eb31SRichard Henderson res = tmp; 674a751eb31SRichard Henderson } 675b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 676b2167459SRichard Henderson break; 677b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 678aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6796fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 680a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 6816fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, tmp); 682a751eb31SRichard Henderson } 683b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_LT, tmp); 684b2167459SRichard Henderson break; 685b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 686b47a4a02SSven Schnelle /* 687b47a4a02SSven Schnelle * Simplify: 688b47a4a02SSven Schnelle * (N ^ V) | Z 689b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 690b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 691b47a4a02SSven Schnelle * (~(res ^ sv) >= 0) | !res 692b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31) | !res 693b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31 & res) 694b47a4a02SSven Schnelle */ 695aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 6966fd0c7bcSRichard Henderson tcg_gen_eqv_i64(tmp, res, sv); 697a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 6986fd0c7bcSRichard Henderson tcg_gen_sextract_i64(tmp, tmp, 31, 1); 6996fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 7006fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 701a751eb31SRichard Henderson } else { 7026fd0c7bcSRichard Henderson tcg_gen_sari_i64(tmp, tmp, 63); 7036fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 704a751eb31SRichard Henderson } 705b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 706b2167459SRichard Henderson break; 707b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 708a751eb31SRichard Henderson /* Only bit 0 of cb_msb is ever set. */ 709b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 710b2167459SRichard Henderson break; 711b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 712aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7136fd0c7bcSRichard Henderson tcg_gen_neg_i64(tmp, cb_msb); 7146fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 715a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7166fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 717a751eb31SRichard Henderson } 718b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 719b2167459SRichard Henderson break; 720b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 721a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 722aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7236fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, sv); 724a751eb31SRichard Henderson sv = tmp; 725a751eb31SRichard Henderson } 726b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 727b2167459SRichard Henderson break; 728b2167459SRichard Henderson case 7: /* OD / EV */ 729aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7306fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, res, 1); 731b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_NE, tmp); 732b2167459SRichard Henderson break; 733b2167459SRichard Henderson default: 734b2167459SRichard Henderson g_assert_not_reached(); 735b2167459SRichard Henderson } 736b2167459SRichard Henderson if (cf & 1) { 737b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 738b2167459SRichard Henderson } 739b2167459SRichard Henderson 740b2167459SRichard Henderson return cond; 741b2167459SRichard Henderson } 742b2167459SRichard Henderson 743b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 744b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 745b2167459SRichard Henderson deleted as unused. */ 746b2167459SRichard Henderson 7474fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 7486fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 7496fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 750b2167459SRichard Henderson { 7514fe9533aSRichard Henderson TCGCond tc; 7524fe9533aSRichard Henderson bool ext_uns; 753b2167459SRichard Henderson 754b2167459SRichard Henderson switch (cf >> 1) { 755b2167459SRichard Henderson case 1: /* = / <> */ 7564fe9533aSRichard Henderson tc = TCG_COND_EQ; 7574fe9533aSRichard Henderson ext_uns = true; 758b2167459SRichard Henderson break; 759b2167459SRichard Henderson case 2: /* < / >= */ 7604fe9533aSRichard Henderson tc = TCG_COND_LT; 7614fe9533aSRichard Henderson ext_uns = false; 762b2167459SRichard Henderson break; 763b2167459SRichard Henderson case 3: /* <= / > */ 7644fe9533aSRichard Henderson tc = TCG_COND_LE; 7654fe9533aSRichard Henderson ext_uns = false; 766b2167459SRichard Henderson break; 767b2167459SRichard Henderson case 4: /* << / >>= */ 7684fe9533aSRichard Henderson tc = TCG_COND_LTU; 7694fe9533aSRichard Henderson ext_uns = true; 770b2167459SRichard Henderson break; 771b2167459SRichard Henderson case 5: /* <<= / >> */ 7724fe9533aSRichard Henderson tc = TCG_COND_LEU; 7734fe9533aSRichard Henderson ext_uns = true; 774b2167459SRichard Henderson break; 775b2167459SRichard Henderson default: 776a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 777b2167459SRichard Henderson } 778b2167459SRichard Henderson 7794fe9533aSRichard Henderson if (cf & 1) { 7804fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 7814fe9533aSRichard Henderson } 7824fe9533aSRichard Henderson if (cond_need_ext(ctx, d)) { 783aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 784aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 7854fe9533aSRichard Henderson 7864fe9533aSRichard Henderson if (ext_uns) { 7876fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 7886fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 7894fe9533aSRichard Henderson } else { 7906fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 7916fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 7924fe9533aSRichard Henderson } 7934fe9533aSRichard Henderson return cond_make_tmp(tc, t1, t2); 7944fe9533aSRichard Henderson } 7954fe9533aSRichard Henderson return cond_make(tc, in1, in2); 796b2167459SRichard Henderson } 797b2167459SRichard Henderson 798df0232feSRichard Henderson /* 799df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 800df0232feSRichard Henderson * computed, and use of them is undefined. 801df0232feSRichard Henderson * 802df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 803df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 804df0232feSRichard Henderson * how cases c={2,3} are treated. 805df0232feSRichard Henderson */ 806b2167459SRichard Henderson 807b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 8086fd0c7bcSRichard Henderson TCGv_i64 res) 809b2167459SRichard Henderson { 810b5af8423SRichard Henderson TCGCond tc; 811b5af8423SRichard Henderson bool ext_uns; 812a751eb31SRichard Henderson 813df0232feSRichard Henderson switch (cf) { 814df0232feSRichard Henderson case 0: /* never */ 815df0232feSRichard Henderson case 9: /* undef, C */ 816df0232feSRichard Henderson case 11: /* undef, C & !Z */ 817df0232feSRichard Henderson case 12: /* undef, V */ 818df0232feSRichard Henderson return cond_make_f(); 819df0232feSRichard Henderson 820df0232feSRichard Henderson case 1: /* true */ 821df0232feSRichard Henderson case 8: /* undef, !C */ 822df0232feSRichard Henderson case 10: /* undef, !C | Z */ 823df0232feSRichard Henderson case 13: /* undef, !V */ 824df0232feSRichard Henderson return cond_make_t(); 825df0232feSRichard Henderson 826df0232feSRichard Henderson case 2: /* == */ 827b5af8423SRichard Henderson tc = TCG_COND_EQ; 828b5af8423SRichard Henderson ext_uns = true; 829b5af8423SRichard Henderson break; 830df0232feSRichard Henderson case 3: /* <> */ 831b5af8423SRichard Henderson tc = TCG_COND_NE; 832b5af8423SRichard Henderson ext_uns = true; 833b5af8423SRichard Henderson break; 834df0232feSRichard Henderson case 4: /* < */ 835b5af8423SRichard Henderson tc = TCG_COND_LT; 836b5af8423SRichard Henderson ext_uns = false; 837b5af8423SRichard Henderson break; 838df0232feSRichard Henderson case 5: /* >= */ 839b5af8423SRichard Henderson tc = TCG_COND_GE; 840b5af8423SRichard Henderson ext_uns = false; 841b5af8423SRichard Henderson break; 842df0232feSRichard Henderson case 6: /* <= */ 843b5af8423SRichard Henderson tc = TCG_COND_LE; 844b5af8423SRichard Henderson ext_uns = false; 845b5af8423SRichard Henderson break; 846df0232feSRichard Henderson case 7: /* > */ 847b5af8423SRichard Henderson tc = TCG_COND_GT; 848b5af8423SRichard Henderson ext_uns = false; 849b5af8423SRichard Henderson break; 850df0232feSRichard Henderson 851df0232feSRichard Henderson case 14: /* OD */ 852df0232feSRichard Henderson case 15: /* EV */ 853a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, NULL); 854df0232feSRichard Henderson 855df0232feSRichard Henderson default: 856df0232feSRichard Henderson g_assert_not_reached(); 857b2167459SRichard Henderson } 858b5af8423SRichard Henderson 859b5af8423SRichard Henderson if (cond_need_ext(ctx, d)) { 860aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 861b5af8423SRichard Henderson 862b5af8423SRichard Henderson if (ext_uns) { 8636fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 864b5af8423SRichard Henderson } else { 8656fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 866b5af8423SRichard Henderson } 867b5af8423SRichard Henderson return cond_make_0_tmp(tc, tmp); 868b5af8423SRichard Henderson } 869b5af8423SRichard Henderson return cond_make_0(tc, res); 870b2167459SRichard Henderson } 871b2167459SRichard Henderson 87298cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 87398cd9ca7SRichard Henderson 8744fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 8756fd0c7bcSRichard Henderson TCGv_i64 res) 87698cd9ca7SRichard Henderson { 87798cd9ca7SRichard Henderson unsigned c, f; 87898cd9ca7SRichard Henderson 87998cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 88098cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 88198cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 88298cd9ca7SRichard Henderson c = orig & 3; 88398cd9ca7SRichard Henderson if (c == 3) { 88498cd9ca7SRichard Henderson c = 7; 88598cd9ca7SRichard Henderson } 88698cd9ca7SRichard Henderson f = (orig & 4) / 4; 88798cd9ca7SRichard Henderson 888b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 88998cd9ca7SRichard Henderson } 89098cd9ca7SRichard Henderson 891b2167459SRichard Henderson /* Similar, but for unit conditions. */ 892b2167459SRichard Henderson 8936fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res, 8946fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 895b2167459SRichard Henderson { 896b2167459SRichard Henderson DisasCond cond; 8976fd0c7bcSRichard Henderson TCGv_i64 tmp, cb = NULL; 898c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 899b2167459SRichard Henderson 900b2167459SRichard Henderson if (cf & 8) { 901b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 902b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 903b2167459SRichard Henderson * leaves us with carry bits spread across two words. 904b2167459SRichard Henderson */ 905aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 906aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9076fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, in1, in2); 9086fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, in1, in2); 9096fd0c7bcSRichard Henderson tcg_gen_andc_i64(cb, cb, res); 9106fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, cb, tmp); 911b2167459SRichard Henderson } 912b2167459SRichard Henderson 913b2167459SRichard Henderson switch (cf >> 1) { 914b2167459SRichard Henderson case 0: /* never / TR */ 915b2167459SRichard Henderson case 1: /* undefined */ 916b2167459SRichard Henderson case 5: /* undefined */ 917b2167459SRichard Henderson cond = cond_make_f(); 918b2167459SRichard Henderson break; 919b2167459SRichard Henderson 920b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 921b2167459SRichard Henderson /* See hasless(v,1) from 922b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 923b2167459SRichard Henderson */ 924aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9256fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u); 9266fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9276fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u); 928b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 929b2167459SRichard Henderson break; 930b2167459SRichard Henderson 931b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 932aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9336fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u); 9346fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9356fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u); 936b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 937b2167459SRichard Henderson break; 938b2167459SRichard Henderson 939b2167459SRichard Henderson case 4: /* SDC / NDC */ 9406fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u); 941b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 942b2167459SRichard Henderson break; 943b2167459SRichard Henderson 944b2167459SRichard Henderson case 6: /* SBC / NBC */ 9456fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u); 946b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 947b2167459SRichard Henderson break; 948b2167459SRichard Henderson 949b2167459SRichard Henderson case 7: /* SHC / NHC */ 9506fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u); 951b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 952b2167459SRichard Henderson break; 953b2167459SRichard Henderson 954b2167459SRichard Henderson default: 955b2167459SRichard Henderson g_assert_not_reached(); 956b2167459SRichard Henderson } 957b2167459SRichard Henderson if (cf & 1) { 958b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 959b2167459SRichard Henderson } 960b2167459SRichard Henderson 961b2167459SRichard Henderson return cond; 962b2167459SRichard Henderson } 963b2167459SRichard Henderson 9646fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 9656fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 96672ca8753SRichard Henderson { 96772ca8753SRichard Henderson if (cond_need_ext(ctx, d)) { 968aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 9696fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 97072ca8753SRichard Henderson return t; 97172ca8753SRichard Henderson } 97272ca8753SRichard Henderson return cb_msb; 97372ca8753SRichard Henderson } 97472ca8753SRichard Henderson 9756fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 97672ca8753SRichard Henderson { 97772ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 97872ca8753SRichard Henderson } 97972ca8753SRichard Henderson 980b2167459SRichard Henderson /* Compute signed overflow for addition. */ 9816fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 9826fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 983b2167459SRichard Henderson { 984aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 985aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 986b2167459SRichard Henderson 9876fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 9886fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 9896fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 990b2167459SRichard Henderson 991b2167459SRichard Henderson return sv; 992b2167459SRichard Henderson } 993b2167459SRichard Henderson 994b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 9956fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 9966fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 997b2167459SRichard Henderson { 998aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 999aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1000b2167459SRichard Henderson 10016fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10026fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10036fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 1004b2167459SRichard Henderson 1005b2167459SRichard Henderson return sv; 1006b2167459SRichard Henderson } 1007b2167459SRichard Henderson 10086fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 10096fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1010faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1011b2167459SRichard Henderson { 10126fd0c7bcSRichard Henderson TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp; 1013b2167459SRichard Henderson unsigned c = cf >> 1; 1014b2167459SRichard Henderson DisasCond cond; 1015b2167459SRichard Henderson 1016aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1017f764718dSRichard Henderson cb = NULL; 1018f764718dSRichard Henderson cb_msb = NULL; 1019bdcccc17SRichard Henderson cb_cond = NULL; 1020b2167459SRichard Henderson 1021b2167459SRichard Henderson if (shift) { 1022aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10236fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1024b2167459SRichard Henderson in1 = tmp; 1025b2167459SRichard Henderson } 1026b2167459SRichard Henderson 1027b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1028aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1029aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1030bdcccc17SRichard Henderson 1031a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1032b2167459SRichard Henderson if (is_c) { 10336fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1034a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1035b2167459SRichard Henderson } 10366fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 10376fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1038bdcccc17SRichard Henderson if (cond_need_cb(c)) { 1039bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 1040b2167459SRichard Henderson } 1041b2167459SRichard Henderson } else { 10426fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1043b2167459SRichard Henderson if (is_c) { 10446fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1045b2167459SRichard Henderson } 1046b2167459SRichard Henderson } 1047b2167459SRichard Henderson 1048b2167459SRichard Henderson /* Compute signed overflow if required. */ 1049f764718dSRichard Henderson sv = NULL; 1050b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1051b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 1052b2167459SRichard Henderson if (is_tsv) { 1053b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 1054ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1055b2167459SRichard Henderson } 1056b2167459SRichard Henderson } 1057b2167459SRichard Henderson 1058b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1059a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, cb_cond, sv); 1060b2167459SRichard Henderson if (is_tc) { 1061aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10626fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1063ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1064b2167459SRichard Henderson } 1065b2167459SRichard Henderson 1066b2167459SRichard Henderson /* Write back the result. */ 1067b2167459SRichard Henderson if (!is_l) { 1068b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1069b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1070b2167459SRichard Henderson } 1071b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1072b2167459SRichard Henderson 1073b2167459SRichard Henderson /* Install the new nullification. */ 1074b2167459SRichard Henderson cond_free(&ctx->null_cond); 1075b2167459SRichard Henderson ctx->null_cond = cond; 1076b2167459SRichard Henderson } 1077b2167459SRichard Henderson 1078faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 10790c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 10800c982a28SRichard Henderson { 10816fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 10820c982a28SRichard Henderson 10830c982a28SRichard Henderson if (a->cf) { 10840c982a28SRichard Henderson nullify_over(ctx); 10850c982a28SRichard Henderson } 10860c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 10870c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1088faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1089faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 10900c982a28SRichard Henderson return nullify_end(ctx); 10910c982a28SRichard Henderson } 10920c982a28SRichard Henderson 10930588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 10940588e061SRichard Henderson bool is_tsv, bool is_tc) 10950588e061SRichard Henderson { 10966fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 10970588e061SRichard Henderson 10980588e061SRichard Henderson if (a->cf) { 10990588e061SRichard Henderson nullify_over(ctx); 11000588e061SRichard Henderson } 11016fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11020588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1103faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1104faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 11050588e061SRichard Henderson return nullify_end(ctx); 11060588e061SRichard Henderson } 11070588e061SRichard Henderson 11086fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 11096fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 111063c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1111b2167459SRichard Henderson { 1112a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1113b2167459SRichard Henderson unsigned c = cf >> 1; 1114b2167459SRichard Henderson DisasCond cond; 1115b2167459SRichard Henderson 1116aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1117aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1118aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1119b2167459SRichard Henderson 1120b2167459SRichard Henderson if (is_b) { 1121b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 11226fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1123a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1124a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1125a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 11266fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 11276fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1128b2167459SRichard Henderson } else { 1129bdcccc17SRichard Henderson /* 1130bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1131bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1132bdcccc17SRichard Henderson */ 11336fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1134a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 11356fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 11366fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1137b2167459SRichard Henderson } 1138b2167459SRichard Henderson 1139b2167459SRichard Henderson /* Compute signed overflow if required. */ 1140f764718dSRichard Henderson sv = NULL; 1141b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1142b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1143b2167459SRichard Henderson if (is_tsv) { 1144ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1145b2167459SRichard Henderson } 1146b2167459SRichard Henderson } 1147b2167459SRichard Henderson 1148b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1149b2167459SRichard Henderson if (!is_b) { 11504fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1151b2167459SRichard Henderson } else { 1152a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1153b2167459SRichard Henderson } 1154b2167459SRichard Henderson 1155b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1156b2167459SRichard Henderson if (is_tc) { 1157aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11586fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1159ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1160b2167459SRichard Henderson } 1161b2167459SRichard Henderson 1162b2167459SRichard Henderson /* Write back the result. */ 1163b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1164b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1165b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1166b2167459SRichard Henderson 1167b2167459SRichard Henderson /* Install the new nullification. */ 1168b2167459SRichard Henderson cond_free(&ctx->null_cond); 1169b2167459SRichard Henderson ctx->null_cond = cond; 1170b2167459SRichard Henderson } 1171b2167459SRichard Henderson 117263c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 11730c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 11740c982a28SRichard Henderson { 11756fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 11760c982a28SRichard Henderson 11770c982a28SRichard Henderson if (a->cf) { 11780c982a28SRichard Henderson nullify_over(ctx); 11790c982a28SRichard Henderson } 11800c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 11810c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 118263c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 11830c982a28SRichard Henderson return nullify_end(ctx); 11840c982a28SRichard Henderson } 11850c982a28SRichard Henderson 11860588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 11870588e061SRichard Henderson { 11886fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11890588e061SRichard Henderson 11900588e061SRichard Henderson if (a->cf) { 11910588e061SRichard Henderson nullify_over(ctx); 11920588e061SRichard Henderson } 11936fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11940588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 119563c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 119663c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 11970588e061SRichard Henderson return nullify_end(ctx); 11980588e061SRichard Henderson } 11990588e061SRichard Henderson 12006fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12016fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1202b2167459SRichard Henderson { 12036fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1204b2167459SRichard Henderson DisasCond cond; 1205b2167459SRichard Henderson 1206aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 12076fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1208b2167459SRichard Henderson 1209b2167459SRichard Henderson /* Compute signed overflow if required. */ 1210f764718dSRichard Henderson sv = NULL; 1211b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1212b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1213b2167459SRichard Henderson } 1214b2167459SRichard Henderson 1215b2167459SRichard Henderson /* Form the condition for the compare. */ 12164fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1217b2167459SRichard Henderson 1218b2167459SRichard Henderson /* Clear. */ 12196fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1220b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1221b2167459SRichard Henderson 1222b2167459SRichard Henderson /* Install the new nullification. */ 1223b2167459SRichard Henderson cond_free(&ctx->null_cond); 1224b2167459SRichard Henderson ctx->null_cond = cond; 1225b2167459SRichard Henderson } 1226b2167459SRichard Henderson 12276fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12286fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 12296fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1230b2167459SRichard Henderson { 12316fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1232b2167459SRichard Henderson 1233b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1234b2167459SRichard Henderson fn(dest, in1, in2); 1235b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1236b2167459SRichard Henderson 1237b2167459SRichard Henderson /* Install the new nullification. */ 1238b2167459SRichard Henderson cond_free(&ctx->null_cond); 1239b2167459SRichard Henderson if (cf) { 1240b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1241b2167459SRichard Henderson } 1242b2167459SRichard Henderson } 1243b2167459SRichard Henderson 1244fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12456fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 12460c982a28SRichard Henderson { 12476fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12480c982a28SRichard Henderson 12490c982a28SRichard Henderson if (a->cf) { 12500c982a28SRichard Henderson nullify_over(ctx); 12510c982a28SRichard Henderson } 12520c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12530c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1254fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 12550c982a28SRichard Henderson return nullify_end(ctx); 12560c982a28SRichard Henderson } 12570c982a28SRichard Henderson 12586fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12596fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, bool is_tc, 12606fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1261b2167459SRichard Henderson { 12626fd0c7bcSRichard Henderson TCGv_i64 dest; 1263b2167459SRichard Henderson DisasCond cond; 1264b2167459SRichard Henderson 1265b2167459SRichard Henderson if (cf == 0) { 1266b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 1267b2167459SRichard Henderson fn(dest, in1, in2); 1268b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1269b2167459SRichard Henderson cond_free(&ctx->null_cond); 1270b2167459SRichard Henderson } else { 1271aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1272b2167459SRichard Henderson fn(dest, in1, in2); 1273b2167459SRichard Henderson 127459963d8fSRichard Henderson cond = do_unit_cond(cf, d, dest, in1, in2); 1275b2167459SRichard Henderson 1276b2167459SRichard Henderson if (is_tc) { 1277aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 12786fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1279ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1280b2167459SRichard Henderson } 1281b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1282b2167459SRichard Henderson 1283b2167459SRichard Henderson cond_free(&ctx->null_cond); 1284b2167459SRichard Henderson ctx->null_cond = cond; 1285b2167459SRichard Henderson } 1286b2167459SRichard Henderson } 1287b2167459SRichard Henderson 128886f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 12898d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 12908d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 12918d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 12928d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 12936fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 129486f8d05fSRichard Henderson { 129586f8d05fSRichard Henderson TCGv_ptr ptr; 12966fd0c7bcSRichard Henderson TCGv_i64 tmp; 129786f8d05fSRichard Henderson TCGv_i64 spc; 129886f8d05fSRichard Henderson 129986f8d05fSRichard Henderson if (sp != 0) { 13008d6ae7fbSRichard Henderson if (sp < 0) { 13018d6ae7fbSRichard Henderson sp = ~sp; 13028d6ae7fbSRichard Henderson } 13036fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 13048d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 13058d6ae7fbSRichard Henderson return spc; 130686f8d05fSRichard Henderson } 1307494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1308494737b7SRichard Henderson return cpu_srH; 1309494737b7SRichard Henderson } 131086f8d05fSRichard Henderson 131186f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1312aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 13136fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 131486f8d05fSRichard Henderson 1315698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 13166fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 13176fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 13186fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 131986f8d05fSRichard Henderson 1320ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 132186f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 132286f8d05fSRichard Henderson 132386f8d05fSRichard Henderson return spc; 132486f8d05fSRichard Henderson } 132586f8d05fSRichard Henderson #endif 132686f8d05fSRichard Henderson 13276fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1328c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 132986f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 133086f8d05fSRichard Henderson { 13316fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 13326fd0c7bcSRichard Henderson TCGv_i64 ofs; 13336fd0c7bcSRichard Henderson TCGv_i64 addr; 133486f8d05fSRichard Henderson 1335*f5b5c857SRichard Henderson set_insn_breg(ctx, rb); 1336*f5b5c857SRichard Henderson 133786f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 133886f8d05fSRichard Henderson if (rx) { 1339aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13406fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 13416fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 134286f8d05fSRichard Henderson } else if (disp || modify) { 1343aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13446fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 134586f8d05fSRichard Henderson } else { 134686f8d05fSRichard Henderson ofs = base; 134786f8d05fSRichard Henderson } 134886f8d05fSRichard Henderson 134986f8d05fSRichard Henderson *pofs = ofs; 13506fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 1351d265360fSRichard Henderson tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx)); 1352698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 135386f8d05fSRichard Henderson if (!is_phys) { 1354d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 135586f8d05fSRichard Henderson } 135686f8d05fSRichard Henderson #endif 135786f8d05fSRichard Henderson } 135886f8d05fSRichard Henderson 135996d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 136096d6407fSRichard Henderson * < 0 for pre-modify, 136196d6407fSRichard Henderson * > 0 for post-modify, 136296d6407fSRichard Henderson * = 0 for no base register update. 136396d6407fSRichard Henderson */ 136496d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1365c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 136614776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 136796d6407fSRichard Henderson { 13686fd0c7bcSRichard Henderson TCGv_i64 ofs; 13696fd0c7bcSRichard Henderson TCGv_i64 addr; 137096d6407fSRichard Henderson 137196d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 137296d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 137396d6407fSRichard Henderson 137486f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 137586f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1376c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 137786f8d05fSRichard Henderson if (modify) { 137886f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 137996d6407fSRichard Henderson } 138096d6407fSRichard Henderson } 138196d6407fSRichard Henderson 138296d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1383c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 138414776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 138596d6407fSRichard Henderson { 13866fd0c7bcSRichard Henderson TCGv_i64 ofs; 13876fd0c7bcSRichard Henderson TCGv_i64 addr; 138896d6407fSRichard Henderson 138996d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 139096d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 139196d6407fSRichard Henderson 139286f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 139386f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1394217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 139586f8d05fSRichard Henderson if (modify) { 139686f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 139796d6407fSRichard Henderson } 139896d6407fSRichard Henderson } 139996d6407fSRichard Henderson 140096d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1401c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 140214776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 140396d6407fSRichard Henderson { 14046fd0c7bcSRichard Henderson TCGv_i64 ofs; 14056fd0c7bcSRichard Henderson TCGv_i64 addr; 140696d6407fSRichard Henderson 140796d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 140896d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 140996d6407fSRichard Henderson 141086f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 141186f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1412217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 141386f8d05fSRichard Henderson if (modify) { 141486f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 141596d6407fSRichard Henderson } 141696d6407fSRichard Henderson } 141796d6407fSRichard Henderson 141896d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1419c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 142014776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 142196d6407fSRichard Henderson { 14226fd0c7bcSRichard Henderson TCGv_i64 ofs; 14236fd0c7bcSRichard Henderson TCGv_i64 addr; 142496d6407fSRichard Henderson 142596d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 142696d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 142796d6407fSRichard Henderson 142886f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 142986f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 1430217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 143186f8d05fSRichard Henderson if (modify) { 143286f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 143396d6407fSRichard Henderson } 143496d6407fSRichard Henderson } 143596d6407fSRichard Henderson 14361cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1437c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 143814776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 143996d6407fSRichard Henderson { 14406fd0c7bcSRichard Henderson TCGv_i64 dest; 144196d6407fSRichard Henderson 144296d6407fSRichard Henderson nullify_over(ctx); 144396d6407fSRichard Henderson 144496d6407fSRichard Henderson if (modify == 0) { 144596d6407fSRichard Henderson /* No base register update. */ 144696d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 144796d6407fSRichard Henderson } else { 144896d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1449aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 145096d6407fSRichard Henderson } 14516fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 145296d6407fSRichard Henderson save_gpr(ctx, rt, dest); 145396d6407fSRichard Henderson 14541cd012a5SRichard Henderson return nullify_end(ctx); 145596d6407fSRichard Henderson } 145696d6407fSRichard Henderson 1457740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1458c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 145986f8d05fSRichard Henderson unsigned sp, int modify) 146096d6407fSRichard Henderson { 146196d6407fSRichard Henderson TCGv_i32 tmp; 146296d6407fSRichard Henderson 146396d6407fSRichard Henderson nullify_over(ctx); 146496d6407fSRichard Henderson 146596d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 146686f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 146796d6407fSRichard Henderson save_frw_i32(rt, tmp); 146896d6407fSRichard Henderson 146996d6407fSRichard Henderson if (rt == 0) { 1470ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 147196d6407fSRichard Henderson } 147296d6407fSRichard Henderson 1473740038d7SRichard Henderson return nullify_end(ctx); 147496d6407fSRichard Henderson } 147596d6407fSRichard Henderson 1476740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1477740038d7SRichard Henderson { 1478740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1479740038d7SRichard Henderson a->disp, a->sp, a->m); 1480740038d7SRichard Henderson } 1481740038d7SRichard Henderson 1482740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1483c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 148486f8d05fSRichard Henderson unsigned sp, int modify) 148596d6407fSRichard Henderson { 148696d6407fSRichard Henderson TCGv_i64 tmp; 148796d6407fSRichard Henderson 148896d6407fSRichard Henderson nullify_over(ctx); 148996d6407fSRichard Henderson 149096d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1491fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 149296d6407fSRichard Henderson save_frd(rt, tmp); 149396d6407fSRichard Henderson 149496d6407fSRichard Henderson if (rt == 0) { 1495ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 149696d6407fSRichard Henderson } 149796d6407fSRichard Henderson 1498740038d7SRichard Henderson return nullify_end(ctx); 1499740038d7SRichard Henderson } 1500740038d7SRichard Henderson 1501740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1502740038d7SRichard Henderson { 1503740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1504740038d7SRichard Henderson a->disp, a->sp, a->m); 150596d6407fSRichard Henderson } 150696d6407fSRichard Henderson 15071cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1508c53e401eSRichard Henderson int64_t disp, unsigned sp, 150914776ab5STony Nguyen int modify, MemOp mop) 151096d6407fSRichard Henderson { 151196d6407fSRichard Henderson nullify_over(ctx); 15126fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 15131cd012a5SRichard Henderson return nullify_end(ctx); 151496d6407fSRichard Henderson } 151596d6407fSRichard Henderson 1516740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1517c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 151886f8d05fSRichard Henderson unsigned sp, int modify) 151996d6407fSRichard Henderson { 152096d6407fSRichard Henderson TCGv_i32 tmp; 152196d6407fSRichard Henderson 152296d6407fSRichard Henderson nullify_over(ctx); 152396d6407fSRichard Henderson 152496d6407fSRichard Henderson tmp = load_frw_i32(rt); 152586f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 152696d6407fSRichard Henderson 1527740038d7SRichard Henderson return nullify_end(ctx); 152896d6407fSRichard Henderson } 152996d6407fSRichard Henderson 1530740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1531740038d7SRichard Henderson { 1532740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1533740038d7SRichard Henderson a->disp, a->sp, a->m); 1534740038d7SRichard Henderson } 1535740038d7SRichard Henderson 1536740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1537c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 153886f8d05fSRichard Henderson unsigned sp, int modify) 153996d6407fSRichard Henderson { 154096d6407fSRichard Henderson TCGv_i64 tmp; 154196d6407fSRichard Henderson 154296d6407fSRichard Henderson nullify_over(ctx); 154396d6407fSRichard Henderson 154496d6407fSRichard Henderson tmp = load_frd(rt); 1545fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 154696d6407fSRichard Henderson 1547740038d7SRichard Henderson return nullify_end(ctx); 1548740038d7SRichard Henderson } 1549740038d7SRichard Henderson 1550740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1551740038d7SRichard Henderson { 1552740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1553740038d7SRichard Henderson a->disp, a->sp, a->m); 155496d6407fSRichard Henderson } 155596d6407fSRichard Henderson 15561ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1557ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1558ebe9383cSRichard Henderson { 1559ebe9383cSRichard Henderson TCGv_i32 tmp; 1560ebe9383cSRichard Henderson 1561ebe9383cSRichard Henderson nullify_over(ctx); 1562ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1563ebe9383cSRichard Henderson 1564ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1565ebe9383cSRichard Henderson 1566ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 15671ca74648SRichard Henderson return nullify_end(ctx); 1568ebe9383cSRichard Henderson } 1569ebe9383cSRichard Henderson 15701ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1571ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1572ebe9383cSRichard Henderson { 1573ebe9383cSRichard Henderson TCGv_i32 dst; 1574ebe9383cSRichard Henderson TCGv_i64 src; 1575ebe9383cSRichard Henderson 1576ebe9383cSRichard Henderson nullify_over(ctx); 1577ebe9383cSRichard Henderson src = load_frd(ra); 1578ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1579ebe9383cSRichard Henderson 1580ad75a51eSRichard Henderson func(dst, tcg_env, src); 1581ebe9383cSRichard Henderson 1582ebe9383cSRichard Henderson save_frw_i32(rt, dst); 15831ca74648SRichard Henderson return nullify_end(ctx); 1584ebe9383cSRichard Henderson } 1585ebe9383cSRichard Henderson 15861ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1587ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1588ebe9383cSRichard Henderson { 1589ebe9383cSRichard Henderson TCGv_i64 tmp; 1590ebe9383cSRichard Henderson 1591ebe9383cSRichard Henderson nullify_over(ctx); 1592ebe9383cSRichard Henderson tmp = load_frd0(ra); 1593ebe9383cSRichard Henderson 1594ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1595ebe9383cSRichard Henderson 1596ebe9383cSRichard Henderson save_frd(rt, tmp); 15971ca74648SRichard Henderson return nullify_end(ctx); 1598ebe9383cSRichard Henderson } 1599ebe9383cSRichard Henderson 16001ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1601ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1602ebe9383cSRichard Henderson { 1603ebe9383cSRichard Henderson TCGv_i32 src; 1604ebe9383cSRichard Henderson TCGv_i64 dst; 1605ebe9383cSRichard Henderson 1606ebe9383cSRichard Henderson nullify_over(ctx); 1607ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1608ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1609ebe9383cSRichard Henderson 1610ad75a51eSRichard Henderson func(dst, tcg_env, src); 1611ebe9383cSRichard Henderson 1612ebe9383cSRichard Henderson save_frd(rt, dst); 16131ca74648SRichard Henderson return nullify_end(ctx); 1614ebe9383cSRichard Henderson } 1615ebe9383cSRichard Henderson 16161ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1617ebe9383cSRichard Henderson unsigned ra, unsigned rb, 161831234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1619ebe9383cSRichard Henderson { 1620ebe9383cSRichard Henderson TCGv_i32 a, b; 1621ebe9383cSRichard Henderson 1622ebe9383cSRichard Henderson nullify_over(ctx); 1623ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1624ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1625ebe9383cSRichard Henderson 1626ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1627ebe9383cSRichard Henderson 1628ebe9383cSRichard Henderson save_frw_i32(rt, a); 16291ca74648SRichard Henderson return nullify_end(ctx); 1630ebe9383cSRichard Henderson } 1631ebe9383cSRichard Henderson 16321ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1633ebe9383cSRichard Henderson unsigned ra, unsigned rb, 163431234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1635ebe9383cSRichard Henderson { 1636ebe9383cSRichard Henderson TCGv_i64 a, b; 1637ebe9383cSRichard Henderson 1638ebe9383cSRichard Henderson nullify_over(ctx); 1639ebe9383cSRichard Henderson a = load_frd0(ra); 1640ebe9383cSRichard Henderson b = load_frd0(rb); 1641ebe9383cSRichard Henderson 1642ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1643ebe9383cSRichard Henderson 1644ebe9383cSRichard Henderson save_frd(rt, a); 16451ca74648SRichard Henderson return nullify_end(ctx); 1646ebe9383cSRichard Henderson } 1647ebe9383cSRichard Henderson 164898cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 164998cd9ca7SRichard Henderson have already had nullification handled. */ 1650c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest, 165198cd9ca7SRichard Henderson unsigned link, bool is_n) 165298cd9ca7SRichard Henderson { 165398cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 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 ctx->iaoq_n = dest; 165898cd9ca7SRichard Henderson if (is_n) { 165998cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 166098cd9ca7SRichard Henderson } 166198cd9ca7SRichard Henderson } else { 166298cd9ca7SRichard Henderson nullify_over(ctx); 166398cd9ca7SRichard Henderson 166498cd9ca7SRichard Henderson if (link != 0) { 1665741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 166698cd9ca7SRichard Henderson } 166798cd9ca7SRichard Henderson 166898cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 166998cd9ca7SRichard Henderson nullify_set(ctx, 0); 167098cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 167198cd9ca7SRichard Henderson } else { 167298cd9ca7SRichard Henderson nullify_set(ctx, is_n); 167398cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 167498cd9ca7SRichard Henderson } 167598cd9ca7SRichard Henderson 167631234768SRichard Henderson nullify_end(ctx); 167798cd9ca7SRichard Henderson 167898cd9ca7SRichard Henderson nullify_set(ctx, 0); 167998cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 168031234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 168198cd9ca7SRichard Henderson } 168201afb7beSRichard Henderson return true; 168398cd9ca7SRichard Henderson } 168498cd9ca7SRichard Henderson 168598cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 168698cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1687c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 168898cd9ca7SRichard Henderson DisasCond *cond) 168998cd9ca7SRichard Henderson { 1690c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, disp); 169198cd9ca7SRichard Henderson TCGLabel *taken = NULL; 169298cd9ca7SRichard Henderson TCGCond c = cond->c; 169398cd9ca7SRichard Henderson bool n; 169498cd9ca7SRichard Henderson 169598cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 169698cd9ca7SRichard Henderson 169798cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 169898cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 169901afb7beSRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 170098cd9ca7SRichard Henderson } 170198cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 170201afb7beSRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 170398cd9ca7SRichard Henderson } 170498cd9ca7SRichard Henderson 170598cd9ca7SRichard Henderson taken = gen_new_label(); 17066fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 170798cd9ca7SRichard Henderson cond_free(cond); 170898cd9ca7SRichard Henderson 170998cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 171098cd9ca7SRichard Henderson n = is_n && disp < 0; 171198cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 171298cd9ca7SRichard Henderson nullify_set(ctx, 0); 1713a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 171498cd9ca7SRichard Henderson } else { 171598cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 171698cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 171798cd9ca7SRichard Henderson ctx->null_lab = NULL; 171898cd9ca7SRichard Henderson } 171998cd9ca7SRichard Henderson nullify_set(ctx, n); 1720c301f34eSRichard Henderson if (ctx->iaoq_n == -1) { 1721c301f34eSRichard Henderson /* The temporary iaoq_n_var died at the branch above. 1722c301f34eSRichard Henderson Regenerate it here instead of saving it. */ 17236fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 1724c301f34eSRichard Henderson } 1725a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 172698cd9ca7SRichard Henderson } 172798cd9ca7SRichard Henderson 172898cd9ca7SRichard Henderson gen_set_label(taken); 172998cd9ca7SRichard Henderson 173098cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 173198cd9ca7SRichard Henderson n = is_n && disp >= 0; 173298cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 173398cd9ca7SRichard Henderson nullify_set(ctx, 0); 1734a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, dest, dest + 4); 173598cd9ca7SRichard Henderson } else { 173698cd9ca7SRichard Henderson nullify_set(ctx, n); 1737a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 173898cd9ca7SRichard Henderson } 173998cd9ca7SRichard Henderson 174098cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 174198cd9ca7SRichard Henderson if (ctx->null_lab) { 174298cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 174398cd9ca7SRichard Henderson ctx->null_lab = NULL; 174431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 174598cd9ca7SRichard Henderson } else { 174631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 174798cd9ca7SRichard Henderson } 174801afb7beSRichard Henderson return true; 174998cd9ca7SRichard Henderson } 175098cd9ca7SRichard Henderson 175198cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 175298cd9ca7SRichard Henderson nullification of the branch itself. */ 17536fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest, 175498cd9ca7SRichard Henderson unsigned link, bool is_n) 175598cd9ca7SRichard Henderson { 17566fd0c7bcSRichard Henderson TCGv_i64 a0, a1, next, tmp; 175798cd9ca7SRichard Henderson TCGCond c; 175898cd9ca7SRichard Henderson 175998cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 176098cd9ca7SRichard Henderson 176198cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 176298cd9ca7SRichard Henderson if (link != 0) { 1763741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 176498cd9ca7SRichard Henderson } 1765aac0f603SRichard Henderson next = tcg_temp_new_i64(); 17666fd0c7bcSRichard Henderson tcg_gen_mov_i64(next, dest); 176798cd9ca7SRichard Henderson if (is_n) { 1768c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1769a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next); 17706fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, next, 4); 1771a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 1772c301f34eSRichard Henderson nullify_set(ctx, 0); 177331234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 177401afb7beSRichard Henderson return true; 1775c301f34eSRichard Henderson } 177698cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 177798cd9ca7SRichard Henderson } 1778c301f34eSRichard Henderson ctx->iaoq_n = -1; 1779c301f34eSRichard Henderson ctx->iaoq_n_var = next; 178098cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 178198cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 178298cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 17834137cb83SRichard Henderson tracepoint in effect). Since the goto_ptr that we must use 178498cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 178598cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 178698cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 178798cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 178898cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 178998cd9ca7SRichard Henderson 179098cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 179198cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 179298cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 1793a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest); 1794aac0f603SRichard Henderson next = tcg_temp_new_i64(); 17956fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, dest, 4); 1796a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 179798cd9ca7SRichard Henderson 179898cd9ca7SRichard Henderson nullify_over(ctx); 179998cd9ca7SRichard Henderson if (link != 0) { 18009a91dd84SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 180198cd9ca7SRichard Henderson } 18027f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 180301afb7beSRichard Henderson return nullify_end(ctx); 180498cd9ca7SRichard Henderson } else { 180598cd9ca7SRichard Henderson c = ctx->null_cond.c; 180698cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 180798cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 180898cd9ca7SRichard Henderson 1809aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 1810aac0f603SRichard Henderson next = tcg_temp_new_i64(); 181198cd9ca7SRichard Henderson 1812741322f4SRichard Henderson copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var); 18136fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest); 181498cd9ca7SRichard Henderson ctx->iaoq_n = -1; 181598cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 181698cd9ca7SRichard Henderson 181798cd9ca7SRichard Henderson if (link != 0) { 18186fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 181998cd9ca7SRichard Henderson } 182098cd9ca7SRichard Henderson 182198cd9ca7SRichard Henderson if (is_n) { 182298cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 182398cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 182498cd9ca7SRichard Henderson to the branch. */ 18256fd0c7bcSRichard Henderson tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1); 182698cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 182798cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 182898cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 182998cd9ca7SRichard Henderson } else { 183098cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 183198cd9ca7SRichard Henderson } 183298cd9ca7SRichard Henderson } 183301afb7beSRichard Henderson return true; 183498cd9ca7SRichard Henderson } 183598cd9ca7SRichard Henderson 1836660eefe1SRichard Henderson /* Implement 1837660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1838660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1839660eefe1SRichard Henderson * else 1840660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1841660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1842660eefe1SRichard Henderson */ 18436fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1844660eefe1SRichard Henderson { 18456fd0c7bcSRichard Henderson TCGv_i64 dest; 1846660eefe1SRichard Henderson switch (ctx->privilege) { 1847660eefe1SRichard Henderson case 0: 1848660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 1849660eefe1SRichard Henderson return offset; 1850660eefe1SRichard Henderson case 3: 1851993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 1852aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18536fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1854660eefe1SRichard Henderson break; 1855660eefe1SRichard Henderson default: 1856aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18576fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 18586fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 18596fd0c7bcSRichard Henderson tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset); 1860660eefe1SRichard Henderson break; 1861660eefe1SRichard Henderson } 1862660eefe1SRichard Henderson return dest; 1863660eefe1SRichard Henderson } 1864660eefe1SRichard Henderson 1865ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 18667ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 18677ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 18687ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 18697ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 18707ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 18717ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 18727ad439dfSRichard Henderson aforementioned BE. */ 187331234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 18747ad439dfSRichard Henderson { 18756fd0c7bcSRichard Henderson TCGv_i64 tmp; 1876a0180973SRichard Henderson 18777ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 18787ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 18798b81968cSMichael Tokarev next insn within the privileged page. */ 18807ad439dfSRichard Henderson switch (ctx->null_cond.c) { 18817ad439dfSRichard Henderson case TCG_COND_NEVER: 18827ad439dfSRichard Henderson break; 18837ad439dfSRichard Henderson case TCG_COND_ALWAYS: 18846fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 18857ad439dfSRichard Henderson goto do_sigill; 18867ad439dfSRichard Henderson default: 18877ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 18887ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 18897ad439dfSRichard Henderson g_assert_not_reached(); 18907ad439dfSRichard Henderson } 18917ad439dfSRichard Henderson 18927ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 18937ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 18947ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 18957ad439dfSRichard Henderson under such conditions. */ 18967ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 18977ad439dfSRichard Henderson goto do_sigill; 18987ad439dfSRichard Henderson } 18997ad439dfSRichard Henderson 1900ebd0e151SRichard Henderson switch (ctx->iaoq_f & -4) { 19017ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 19022986721dSRichard Henderson gen_excp_1(EXCP_IMP); 190331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 190431234768SRichard Henderson break; 19057ad439dfSRichard Henderson 19067ad439dfSRichard Henderson case 0xb0: /* LWS */ 19077ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 190831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 190931234768SRichard Henderson break; 19107ad439dfSRichard Henderson 19117ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 19126fd0c7bcSRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27])); 1913aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 19146fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_gr[31], 3); 1915a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 19166fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 1917a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 191831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 191931234768SRichard Henderson break; 19207ad439dfSRichard Henderson 19217ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 19227ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 192331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 192431234768SRichard Henderson break; 19257ad439dfSRichard Henderson 19267ad439dfSRichard Henderson default: 19277ad439dfSRichard Henderson do_sigill: 19282986721dSRichard Henderson gen_excp_1(EXCP_ILL); 192931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 193031234768SRichard Henderson break; 19317ad439dfSRichard Henderson } 19327ad439dfSRichard Henderson } 1933ba1d0b44SRichard Henderson #endif 19347ad439dfSRichard Henderson 1935deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 1936b2167459SRichard Henderson { 1937b2167459SRichard Henderson cond_free(&ctx->null_cond); 193831234768SRichard Henderson return true; 1939b2167459SRichard Henderson } 1940b2167459SRichard Henderson 194140f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 194298a9cb79SRichard Henderson { 194331234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 194498a9cb79SRichard Henderson } 194598a9cb79SRichard Henderson 1946e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 194798a9cb79SRichard Henderson { 194898a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 194998a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 195098a9cb79SRichard Henderson 195198a9cb79SRichard Henderson cond_free(&ctx->null_cond); 195231234768SRichard Henderson return true; 195398a9cb79SRichard Henderson } 195498a9cb79SRichard Henderson 1955c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 195698a9cb79SRichard Henderson { 1957c603e14aSRichard Henderson unsigned rt = a->t; 19586fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, rt); 19596fd0c7bcSRichard Henderson tcg_gen_movi_i64(tmp, ctx->iaoq_f); 196098a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 196198a9cb79SRichard Henderson 196298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 196331234768SRichard Henderson return true; 196498a9cb79SRichard Henderson } 196598a9cb79SRichard Henderson 1966c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 196798a9cb79SRichard Henderson { 1968c603e14aSRichard Henderson unsigned rt = a->t; 1969c603e14aSRichard Henderson unsigned rs = a->sp; 197033423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 197198a9cb79SRichard Henderson 197233423472SRichard Henderson load_spr(ctx, t0, rs); 197333423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 197433423472SRichard Henderson 1975967662cdSRichard Henderson save_gpr(ctx, rt, t0); 197698a9cb79SRichard Henderson 197798a9cb79SRichard Henderson cond_free(&ctx->null_cond); 197831234768SRichard Henderson return true; 197998a9cb79SRichard Henderson } 198098a9cb79SRichard Henderson 1981c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 198298a9cb79SRichard Henderson { 1983c603e14aSRichard Henderson unsigned rt = a->t; 1984c603e14aSRichard Henderson unsigned ctl = a->r; 19856fd0c7bcSRichard Henderson TCGv_i64 tmp; 198698a9cb79SRichard Henderson 198798a9cb79SRichard Henderson switch (ctl) { 198835136a77SRichard Henderson case CR_SAR: 1989c603e14aSRichard Henderson if (a->e == 0) { 199098a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 199198a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 19926fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 199398a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 199435136a77SRichard Henderson goto done; 199598a9cb79SRichard Henderson } 199698a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 199735136a77SRichard Henderson goto done; 199835136a77SRichard Henderson case CR_IT: /* Interval Timer */ 199935136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 200035136a77SRichard Henderson nullify_over(ctx); 200198a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2002dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 200349c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 200431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 200549c29d6cSRichard Henderson } else { 200649c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 200749c29d6cSRichard Henderson } 200898a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 200931234768SRichard Henderson return nullify_end(ctx); 201098a9cb79SRichard Henderson case 26: 201198a9cb79SRichard Henderson case 27: 201298a9cb79SRichard Henderson break; 201398a9cb79SRichard Henderson default: 201498a9cb79SRichard Henderson /* All other control registers are privileged. */ 201535136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 201635136a77SRichard Henderson break; 201798a9cb79SRichard Henderson } 201898a9cb79SRichard Henderson 2019aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20206fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 202135136a77SRichard Henderson save_gpr(ctx, rt, tmp); 202235136a77SRichard Henderson 202335136a77SRichard Henderson done: 202498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 202531234768SRichard Henderson return true; 202698a9cb79SRichard Henderson } 202798a9cb79SRichard Henderson 2028c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 202933423472SRichard Henderson { 2030c603e14aSRichard Henderson unsigned rr = a->r; 2031c603e14aSRichard Henderson unsigned rs = a->sp; 2032967662cdSRichard Henderson TCGv_i64 tmp; 203333423472SRichard Henderson 203433423472SRichard Henderson if (rs >= 5) { 203533423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 203633423472SRichard Henderson } 203733423472SRichard Henderson nullify_over(ctx); 203833423472SRichard Henderson 2039967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2040967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 204133423472SRichard Henderson 204233423472SRichard Henderson if (rs >= 4) { 2043967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2044494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 204533423472SRichard Henderson } else { 2046967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 204733423472SRichard Henderson } 204833423472SRichard Henderson 204931234768SRichard Henderson return nullify_end(ctx); 205033423472SRichard Henderson } 205133423472SRichard Henderson 2052c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 205398a9cb79SRichard Henderson { 2054c603e14aSRichard Henderson unsigned ctl = a->t; 20556fd0c7bcSRichard Henderson TCGv_i64 reg; 20566fd0c7bcSRichard Henderson TCGv_i64 tmp; 205798a9cb79SRichard Henderson 205835136a77SRichard Henderson if (ctl == CR_SAR) { 20594845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2060aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20616fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 206298a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 206398a9cb79SRichard Henderson 206498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 206531234768SRichard Henderson return true; 206698a9cb79SRichard Henderson } 206798a9cb79SRichard Henderson 206835136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 206935136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 207035136a77SRichard Henderson 2071c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 207235136a77SRichard Henderson nullify_over(ctx); 20734c34bab0SHelge Deller 20744c34bab0SHelge Deller if (ctx->is_pa20) { 20754845f015SSven Schnelle reg = load_gpr(ctx, a->r); 20764c34bab0SHelge Deller } else { 20774c34bab0SHelge Deller reg = tcg_temp_new_i64(); 20784c34bab0SHelge Deller tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 20794c34bab0SHelge Deller } 20804845f015SSven Schnelle 208135136a77SRichard Henderson switch (ctl) { 208235136a77SRichard Henderson case CR_IT: 2083ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 208435136a77SRichard Henderson break; 20854f5f2548SRichard Henderson case CR_EIRR: 2086ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 20874f5f2548SRichard Henderson break; 20884f5f2548SRichard Henderson case CR_EIEM: 2089ad75a51eSRichard Henderson gen_helper_write_eiem(tcg_env, reg); 209031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 20914f5f2548SRichard Henderson break; 20924f5f2548SRichard Henderson 209335136a77SRichard Henderson case CR_IIASQ: 209435136a77SRichard Henderson case CR_IIAOQ: 209535136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 209635136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2097aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20986fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 209935136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 21006fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 21016fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 210235136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 210335136a77SRichard Henderson break; 210435136a77SRichard Henderson 2105d5de20bdSSven Schnelle case CR_PID1: 2106d5de20bdSSven Schnelle case CR_PID2: 2107d5de20bdSSven Schnelle case CR_PID3: 2108d5de20bdSSven Schnelle case CR_PID4: 21096fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2110d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2111ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2112d5de20bdSSven Schnelle #endif 2113d5de20bdSSven Schnelle break; 2114d5de20bdSSven Schnelle 211535136a77SRichard Henderson default: 21166fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 211735136a77SRichard Henderson break; 211835136a77SRichard Henderson } 211931234768SRichard Henderson return nullify_end(ctx); 21204f5f2548SRichard Henderson #endif 212135136a77SRichard Henderson } 212235136a77SRichard Henderson 2123c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 212498a9cb79SRichard Henderson { 2125aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 212698a9cb79SRichard Henderson 21276fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 21286fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 212998a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 213098a9cb79SRichard Henderson 213198a9cb79SRichard Henderson cond_free(&ctx->null_cond); 213231234768SRichard Henderson return true; 213398a9cb79SRichard Henderson } 213498a9cb79SRichard Henderson 2135e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 213698a9cb79SRichard Henderson { 21376fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 213898a9cb79SRichard Henderson 21392330504cSHelge Deller #ifdef CONFIG_USER_ONLY 21402330504cSHelge Deller /* We don't implement space registers in user mode. */ 21416fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 21422330504cSHelge Deller #else 2143967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2144967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 21452330504cSHelge Deller #endif 2146e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 214798a9cb79SRichard Henderson 214898a9cb79SRichard Henderson cond_free(&ctx->null_cond); 214931234768SRichard Henderson return true; 215098a9cb79SRichard Henderson } 215198a9cb79SRichard Henderson 2152e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2153e36f27efSRichard Henderson { 2154e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2155e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY 21566fd0c7bcSRichard Henderson TCGv_i64 tmp; 2157e1b5a5edSRichard Henderson 2158e1b5a5edSRichard Henderson nullify_over(ctx); 2159e1b5a5edSRichard Henderson 2160aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21616fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21626fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2163ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2164e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2165e1b5a5edSRichard Henderson 2166e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 216731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 216831234768SRichard Henderson return nullify_end(ctx); 2169e36f27efSRichard Henderson #endif 2170e1b5a5edSRichard Henderson } 2171e1b5a5edSRichard Henderson 2172e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2173e1b5a5edSRichard Henderson { 2174e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2175e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 21766fd0c7bcSRichard Henderson TCGv_i64 tmp; 2177e1b5a5edSRichard Henderson 2178e1b5a5edSRichard Henderson nullify_over(ctx); 2179e1b5a5edSRichard Henderson 2180aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21816fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 21826fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2183ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2184e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2185e1b5a5edSRichard Henderson 2186e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 218731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 218831234768SRichard Henderson return nullify_end(ctx); 2189e36f27efSRichard Henderson #endif 2190e1b5a5edSRichard Henderson } 2191e1b5a5edSRichard Henderson 2192c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2193e1b5a5edSRichard Henderson { 2194e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2195c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 21966fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2197e1b5a5edSRichard Henderson nullify_over(ctx); 2198e1b5a5edSRichard Henderson 2199c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2200aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2201ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2202e1b5a5edSRichard Henderson 2203e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 220431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 220531234768SRichard Henderson return nullify_end(ctx); 2206c603e14aSRichard Henderson #endif 2207e1b5a5edSRichard Henderson } 2208f49b3537SRichard Henderson 2209e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2210f49b3537SRichard Henderson { 2211f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2212e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2213f49b3537SRichard Henderson nullify_over(ctx); 2214f49b3537SRichard Henderson 2215e36f27efSRichard Henderson if (rfi_r) { 2216ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2217f49b3537SRichard Henderson } else { 2218ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2219f49b3537SRichard Henderson } 222031234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 222107ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 222231234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2223f49b3537SRichard Henderson 222431234768SRichard Henderson return nullify_end(ctx); 2225e36f27efSRichard Henderson #endif 2226f49b3537SRichard Henderson } 22276210db05SHelge Deller 2228e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2229e36f27efSRichard Henderson { 2230e36f27efSRichard Henderson return do_rfi(ctx, false); 2231e36f27efSRichard Henderson } 2232e36f27efSRichard Henderson 2233e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2234e36f27efSRichard Henderson { 2235e36f27efSRichard Henderson return do_rfi(ctx, true); 2236e36f27efSRichard Henderson } 2237e36f27efSRichard Henderson 223896927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 22396210db05SHelge Deller { 22406210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 224196927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 22426210db05SHelge Deller nullify_over(ctx); 2243ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 224431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 224531234768SRichard Henderson return nullify_end(ctx); 224696927adbSRichard Henderson #endif 22476210db05SHelge Deller } 224896927adbSRichard Henderson 224996927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 225096927adbSRichard Henderson { 225196927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 225296927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 225396927adbSRichard Henderson nullify_over(ctx); 2254ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 225596927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 225696927adbSRichard Henderson return nullify_end(ctx); 225796927adbSRichard Henderson #endif 225896927adbSRichard Henderson } 2259e1b5a5edSRichard Henderson 22604a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 22614a4554c6SHelge Deller { 22624a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22634a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY 22644a4554c6SHelge Deller nullify_over(ctx); 2265ad75a51eSRichard Henderson gen_helper_getshadowregs(tcg_env); 22664a4554c6SHelge Deller return nullify_end(ctx); 22674a4554c6SHelge Deller #endif 22684a4554c6SHelge Deller } 22694a4554c6SHelge Deller 2270deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 227198a9cb79SRichard Henderson { 2272deee69a1SRichard Henderson if (a->m) { 22736fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 22746fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 22756fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 227698a9cb79SRichard Henderson 227798a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 22786fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2279deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2280deee69a1SRichard Henderson } 228198a9cb79SRichard Henderson cond_free(&ctx->null_cond); 228231234768SRichard Henderson return true; 228398a9cb79SRichard Henderson } 228498a9cb79SRichard Henderson 2285deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 228698a9cb79SRichard Henderson { 22876fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2288eed14219SRichard Henderson TCGv_i32 level, want; 22896fd0c7bcSRichard Henderson TCGv_i64 addr; 229098a9cb79SRichard Henderson 229198a9cb79SRichard Henderson nullify_over(ctx); 229298a9cb79SRichard Henderson 2293deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2294deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2295eed14219SRichard Henderson 2296deee69a1SRichard Henderson if (a->imm) { 229729dd6f64SRichard Henderson level = tcg_constant_i32(a->ri); 229898a9cb79SRichard Henderson } else { 2299eed14219SRichard Henderson level = tcg_temp_new_i32(); 23006fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2301eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 230298a9cb79SRichard Henderson } 230329dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2304eed14219SRichard Henderson 2305ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2306eed14219SRichard Henderson 2307deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 230831234768SRichard Henderson return nullify_end(ctx); 230998a9cb79SRichard Henderson } 231098a9cb79SRichard Henderson 2311deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 23128d6ae7fbSRichard Henderson { 23138577f354SRichard Henderson if (ctx->is_pa20) { 23148577f354SRichard Henderson return false; 23158577f354SRichard Henderson } 2316deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2317deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23186fd0c7bcSRichard Henderson TCGv_i64 addr; 23196fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 23208d6ae7fbSRichard Henderson 23218d6ae7fbSRichard Henderson nullify_over(ctx); 23228d6ae7fbSRichard Henderson 2323deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2324deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2325deee69a1SRichard Henderson if (a->addr) { 23268577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 23278d6ae7fbSRichard Henderson } else { 23288577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 23298d6ae7fbSRichard Henderson } 23308d6ae7fbSRichard Henderson 233132dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 233232dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 233331234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 233431234768SRichard Henderson } 233531234768SRichard Henderson return nullify_end(ctx); 2336deee69a1SRichard Henderson #endif 23378d6ae7fbSRichard Henderson } 233863300a00SRichard Henderson 2339eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 234063300a00SRichard Henderson { 2341deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2342deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23436fd0c7bcSRichard Henderson TCGv_i64 addr; 23446fd0c7bcSRichard Henderson TCGv_i64 ofs; 234563300a00SRichard Henderson 234663300a00SRichard Henderson nullify_over(ctx); 234763300a00SRichard Henderson 2348deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2349eb25d10fSHelge Deller 2350eb25d10fSHelge Deller /* 2351eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2352eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2353eb25d10fSHelge Deller */ 2354eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2355eb25d10fSHelge Deller if (ctx->is_pa20) { 2356eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 235763300a00SRichard Henderson } 2358eb25d10fSHelge Deller 2359eb25d10fSHelge Deller if (local) { 2360eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 236163300a00SRichard Henderson } else { 2362ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 236363300a00SRichard Henderson } 236463300a00SRichard Henderson 2365eb25d10fSHelge Deller if (a->m) { 2366eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2367eb25d10fSHelge Deller } 2368eb25d10fSHelge Deller 2369eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2370eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2371eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2372eb25d10fSHelge Deller } 2373eb25d10fSHelge Deller return nullify_end(ctx); 2374eb25d10fSHelge Deller #endif 2375eb25d10fSHelge Deller } 2376eb25d10fSHelge Deller 2377eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2378eb25d10fSHelge Deller { 2379eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2380eb25d10fSHelge Deller } 2381eb25d10fSHelge Deller 2382eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2383eb25d10fSHelge Deller { 2384eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2385eb25d10fSHelge Deller } 2386eb25d10fSHelge Deller 2387eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2388eb25d10fSHelge Deller { 2389eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2390eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2391eb25d10fSHelge Deller nullify_over(ctx); 2392eb25d10fSHelge Deller 2393eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2394eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2395eb25d10fSHelge Deller 239663300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 239732dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 239831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 239931234768SRichard Henderson } 240031234768SRichard Henderson return nullify_end(ctx); 2401deee69a1SRichard Henderson #endif 240263300a00SRichard Henderson } 24032dfcca9fSRichard Henderson 24046797c315SNick Hudson /* 24056797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 24066797c315SNick Hudson * See 24076797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 24086797c315SNick Hudson * page 13-9 (195/206) 24096797c315SNick Hudson */ 24106797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 24116797c315SNick Hudson { 24128577f354SRichard Henderson if (ctx->is_pa20) { 24138577f354SRichard Henderson return false; 24148577f354SRichard Henderson } 24156797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24166797c315SNick Hudson #ifndef CONFIG_USER_ONLY 24176fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 24186fd0c7bcSRichard Henderson TCGv_i64 reg; 24196797c315SNick Hudson 24206797c315SNick Hudson nullify_over(ctx); 24216797c315SNick Hudson 24226797c315SNick Hudson /* 24236797c315SNick Hudson * FIXME: 24246797c315SNick Hudson * if (not (pcxl or pcxl2)) 24256797c315SNick Hudson * return gen_illegal(ctx); 24266797c315SNick Hudson */ 24276797c315SNick Hudson 24286fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 24296fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 24306fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 24316797c315SNick Hudson 2432ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 24336797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 24346797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2435ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 24366797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 24376797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 24386797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2439d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 24406797c315SNick Hudson 24416797c315SNick Hudson reg = load_gpr(ctx, a->r); 24426797c315SNick Hudson if (a->addr) { 24438577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 24446797c315SNick Hudson } else { 24458577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 24466797c315SNick Hudson } 24476797c315SNick Hudson 24486797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 24496797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 24506797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24516797c315SNick Hudson } 24526797c315SNick Hudson return nullify_end(ctx); 24536797c315SNick Hudson #endif 24546797c315SNick Hudson } 24556797c315SNick Hudson 24568577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 24578577f354SRichard Henderson { 24588577f354SRichard Henderson if (!ctx->is_pa20) { 24598577f354SRichard Henderson return false; 24608577f354SRichard Henderson } 24618577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24628577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 24638577f354SRichard Henderson nullify_over(ctx); 24648577f354SRichard Henderson { 24658577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 24668577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 24678577f354SRichard Henderson 24688577f354SRichard Henderson if (a->data) { 24698577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 24708577f354SRichard Henderson } else { 24718577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 24728577f354SRichard Henderson } 24738577f354SRichard Henderson } 24748577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 24758577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 24768577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24778577f354SRichard Henderson } 24788577f354SRichard Henderson return nullify_end(ctx); 24798577f354SRichard Henderson #endif 24808577f354SRichard Henderson } 24818577f354SRichard Henderson 2482deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 24832dfcca9fSRichard Henderson { 2484deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2485deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24866fd0c7bcSRichard Henderson TCGv_i64 vaddr; 24876fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 24882dfcca9fSRichard Henderson 24892dfcca9fSRichard Henderson nullify_over(ctx); 24902dfcca9fSRichard Henderson 2491deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 24922dfcca9fSRichard Henderson 2493aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2494ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 24952dfcca9fSRichard Henderson 24962dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2497deee69a1SRichard Henderson if (a->m) { 2498deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 24992dfcca9fSRichard Henderson } 2500deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 25012dfcca9fSRichard Henderson 250231234768SRichard Henderson return nullify_end(ctx); 2503deee69a1SRichard Henderson #endif 25042dfcca9fSRichard Henderson } 250543a97b81SRichard Henderson 2506deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 250743a97b81SRichard Henderson { 250843a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 250943a97b81SRichard Henderson 251043a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 251143a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 251243a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 251343a97b81SRichard Henderson since the entire address space is coherent. */ 2514a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 251543a97b81SRichard Henderson 251631234768SRichard Henderson cond_free(&ctx->null_cond); 251731234768SRichard Henderson return true; 251843a97b81SRichard Henderson } 251998a9cb79SRichard Henderson 2520faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2521b2167459SRichard Henderson { 25220c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2523b2167459SRichard Henderson } 2524b2167459SRichard Henderson 2525faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2526b2167459SRichard Henderson { 25270c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2528b2167459SRichard Henderson } 2529b2167459SRichard Henderson 2530faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2531b2167459SRichard Henderson { 25320c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2533b2167459SRichard Henderson } 2534b2167459SRichard Henderson 2535faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2536b2167459SRichard Henderson { 25370c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 25380c982a28SRichard Henderson } 2539b2167459SRichard Henderson 2540faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 25410c982a28SRichard Henderson { 25420c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 25430c982a28SRichard Henderson } 25440c982a28SRichard Henderson 254563c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 25460c982a28SRichard Henderson { 25470c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 25480c982a28SRichard Henderson } 25490c982a28SRichard Henderson 255063c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25510c982a28SRichard Henderson { 25520c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 25530c982a28SRichard Henderson } 25540c982a28SRichard Henderson 255563c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25560c982a28SRichard Henderson { 25570c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 25580c982a28SRichard Henderson } 25590c982a28SRichard Henderson 256063c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 25610c982a28SRichard Henderson { 25620c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 25630c982a28SRichard Henderson } 25640c982a28SRichard Henderson 256563c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 25660c982a28SRichard Henderson { 25670c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 25680c982a28SRichard Henderson } 25690c982a28SRichard Henderson 257063c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25710c982a28SRichard Henderson { 25720c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 25730c982a28SRichard Henderson } 25740c982a28SRichard Henderson 2575fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 25760c982a28SRichard Henderson { 25776fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 25780c982a28SRichard Henderson } 25790c982a28SRichard Henderson 2580fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 25810c982a28SRichard Henderson { 25826fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 25830c982a28SRichard Henderson } 25840c982a28SRichard Henderson 2585fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 25860c982a28SRichard Henderson { 25870c982a28SRichard Henderson if (a->cf == 0) { 25880c982a28SRichard Henderson unsigned r2 = a->r2; 25890c982a28SRichard Henderson unsigned r1 = a->r1; 25900c982a28SRichard Henderson unsigned rt = a->t; 25910c982a28SRichard Henderson 25927aee8189SRichard Henderson if (rt == 0) { /* NOP */ 25937aee8189SRichard Henderson cond_free(&ctx->null_cond); 25947aee8189SRichard Henderson return true; 25957aee8189SRichard Henderson } 25967aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2597b2167459SRichard Henderson if (r1 == 0) { 25986fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 25996fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2600b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2601b2167459SRichard Henderson } else { 2602b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2603b2167459SRichard Henderson } 2604b2167459SRichard Henderson cond_free(&ctx->null_cond); 260531234768SRichard Henderson return true; 2606b2167459SRichard Henderson } 26077aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 26087aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 26097aee8189SRichard Henderson * 26107aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 26117aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 26127aee8189SRichard Henderson * currently implemented as idle. 26137aee8189SRichard Henderson */ 26147aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 26157aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 26167aee8189SRichard Henderson until the next timer interrupt. */ 26177aee8189SRichard Henderson nullify_over(ctx); 26187aee8189SRichard Henderson 26197aee8189SRichard Henderson /* Advance the instruction queue. */ 2620741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 2621741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 26227aee8189SRichard Henderson nullify_set(ctx, 0); 26237aee8189SRichard Henderson 26247aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2625ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 262629dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 26277aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 26287aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 26297aee8189SRichard Henderson 26307aee8189SRichard Henderson return nullify_end(ctx); 26317aee8189SRichard Henderson } 26327aee8189SRichard Henderson #endif 26337aee8189SRichard Henderson } 26346fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 26357aee8189SRichard Henderson } 2636b2167459SRichard Henderson 2637fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2638b2167459SRichard Henderson { 26396fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 26400c982a28SRichard Henderson } 26410c982a28SRichard Henderson 2642345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 26430c982a28SRichard Henderson { 26446fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2645b2167459SRichard Henderson 26460c982a28SRichard Henderson if (a->cf) { 2647b2167459SRichard Henderson nullify_over(ctx); 2648b2167459SRichard Henderson } 26490c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26500c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2651345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 265231234768SRichard Henderson return nullify_end(ctx); 2653b2167459SRichard Henderson } 2654b2167459SRichard Henderson 2655af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2656b2167459SRichard Henderson { 26576fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2658b2167459SRichard Henderson 26590c982a28SRichard Henderson if (a->cf) { 2660b2167459SRichard Henderson nullify_over(ctx); 2661b2167459SRichard Henderson } 26620c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26630c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 26646fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64); 266531234768SRichard Henderson return nullify_end(ctx); 2666b2167459SRichard Henderson } 2667b2167459SRichard Henderson 2668af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2669b2167459SRichard Henderson { 26706fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2671b2167459SRichard Henderson 26720c982a28SRichard Henderson if (a->cf) { 2673b2167459SRichard Henderson nullify_over(ctx); 2674b2167459SRichard Henderson } 26750c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26760c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2677aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 26786fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 26796fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64); 268031234768SRichard Henderson return nullify_end(ctx); 2681b2167459SRichard Henderson } 2682b2167459SRichard Henderson 2683af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2684b2167459SRichard Henderson { 26850c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 26860c982a28SRichard Henderson } 26870c982a28SRichard Henderson 2688af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 26890c982a28SRichard Henderson { 26900c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 26910c982a28SRichard Henderson } 26920c982a28SRichard Henderson 2693af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 26940c982a28SRichard Henderson { 26956fd0c7bcSRichard Henderson TCGv_i64 tmp; 2696b2167459SRichard Henderson 2697b2167459SRichard Henderson nullify_over(ctx); 2698b2167459SRichard Henderson 2699aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 27006fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, cpu_psw_cb, 3); 2701b2167459SRichard Henderson if (!is_i) { 27026fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2703b2167459SRichard Henderson } 27046fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 27056fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 2706af240753SRichard Henderson do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false, 27076fd0c7bcSRichard Henderson is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64); 270831234768SRichard Henderson return nullify_end(ctx); 2709b2167459SRichard Henderson } 2710b2167459SRichard Henderson 2711af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2712b2167459SRichard Henderson { 27130c982a28SRichard Henderson return do_dcor(ctx, a, false); 27140c982a28SRichard Henderson } 27150c982a28SRichard Henderson 2716af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 27170c982a28SRichard Henderson { 27180c982a28SRichard Henderson return do_dcor(ctx, a, true); 27190c982a28SRichard Henderson } 27200c982a28SRichard Henderson 27210c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 27220c982a28SRichard Henderson { 2723a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 27246fd0c7bcSRichard Henderson TCGv_i64 cout; 2725b2167459SRichard Henderson 2726b2167459SRichard Henderson nullify_over(ctx); 2727b2167459SRichard Henderson 27280c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 27290c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2730b2167459SRichard Henderson 2731aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2732aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2733aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2734aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2735b2167459SRichard Henderson 2736b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 27376fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 27386fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2739b2167459SRichard Henderson 274072ca8753SRichard Henderson /* 274172ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 274272ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 274372ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 274472ca8753SRichard Henderson * proper inputs to the addition without movcond. 274572ca8753SRichard Henderson */ 27466fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 27476fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 27486fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 274972ca8753SRichard Henderson 2750a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2751a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2752a4db4a78SRichard Henderson addc, ctx->zero); 2753b2167459SRichard Henderson 2754b2167459SRichard Henderson /* Write back the result register. */ 27550c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2756b2167459SRichard Henderson 2757b2167459SRichard Henderson /* Write back PSW[CB]. */ 27586fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 27596fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2760b2167459SRichard Henderson 2761b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 276272ca8753SRichard Henderson cout = get_psw_carry(ctx, false); 27636fd0c7bcSRichard Henderson tcg_gen_neg_i64(cpu_psw_v, cout); 27646fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2765b2167459SRichard Henderson 2766b2167459SRichard Henderson /* Install the new nullification. */ 27670c982a28SRichard Henderson if (a->cf) { 27686fd0c7bcSRichard Henderson TCGv_i64 sv = NULL; 2769b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2770b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 2771b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 2772b2167459SRichard Henderson } 2773a751eb31SRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv); 2774b2167459SRichard Henderson } 2775b2167459SRichard Henderson 277631234768SRichard Henderson return nullify_end(ctx); 2777b2167459SRichard Henderson } 2778b2167459SRichard Henderson 27790588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2780b2167459SRichard Henderson { 27810588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 27820588e061SRichard Henderson } 27830588e061SRichard Henderson 27840588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 27850588e061SRichard Henderson { 27860588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 27870588e061SRichard Henderson } 27880588e061SRichard Henderson 27890588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 27900588e061SRichard Henderson { 27910588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 27920588e061SRichard Henderson } 27930588e061SRichard Henderson 27940588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 27950588e061SRichard Henderson { 27960588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 27970588e061SRichard Henderson } 27980588e061SRichard Henderson 27990588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 28000588e061SRichard Henderson { 28010588e061SRichard Henderson return do_sub_imm(ctx, a, false); 28020588e061SRichard Henderson } 28030588e061SRichard Henderson 28040588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 28050588e061SRichard Henderson { 28060588e061SRichard Henderson return do_sub_imm(ctx, a, true); 28070588e061SRichard Henderson } 28080588e061SRichard Henderson 2809345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 28100588e061SRichard Henderson { 28116fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 2812b2167459SRichard Henderson 28130588e061SRichard Henderson if (a->cf) { 2814b2167459SRichard Henderson nullify_over(ctx); 2815b2167459SRichard Henderson } 2816b2167459SRichard Henderson 28176fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 28180588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 2819345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2820b2167459SRichard Henderson 282131234768SRichard Henderson return nullify_end(ctx); 2822b2167459SRichard Henderson } 2823b2167459SRichard Henderson 28240843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 28250843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 28260843563fSRichard Henderson { 28270843563fSRichard Henderson TCGv_i64 r1, r2, dest; 28280843563fSRichard Henderson 28290843563fSRichard Henderson if (!ctx->is_pa20) { 28300843563fSRichard Henderson return false; 28310843563fSRichard Henderson } 28320843563fSRichard Henderson 28330843563fSRichard Henderson nullify_over(ctx); 28340843563fSRichard Henderson 28350843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 28360843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 28370843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 28380843563fSRichard Henderson 28390843563fSRichard Henderson fn(dest, r1, r2); 28400843563fSRichard Henderson save_gpr(ctx, a->t, dest); 28410843563fSRichard Henderson 28420843563fSRichard Henderson return nullify_end(ctx); 28430843563fSRichard Henderson } 28440843563fSRichard Henderson 2845151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 2846151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 2847151f309bSRichard Henderson { 2848151f309bSRichard Henderson TCGv_i64 r, dest; 2849151f309bSRichard Henderson 2850151f309bSRichard Henderson if (!ctx->is_pa20) { 2851151f309bSRichard Henderson return false; 2852151f309bSRichard Henderson } 2853151f309bSRichard Henderson 2854151f309bSRichard Henderson nullify_over(ctx); 2855151f309bSRichard Henderson 2856151f309bSRichard Henderson r = load_gpr(ctx, a->r); 2857151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 2858151f309bSRichard Henderson 2859151f309bSRichard Henderson fn(dest, r, a->i); 2860151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 2861151f309bSRichard Henderson 2862151f309bSRichard Henderson return nullify_end(ctx); 2863151f309bSRichard Henderson } 2864151f309bSRichard Henderson 28653bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 28663bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 28673bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 28683bbb8e48SRichard Henderson { 28693bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 28703bbb8e48SRichard Henderson 28713bbb8e48SRichard Henderson if (!ctx->is_pa20) { 28723bbb8e48SRichard Henderson return false; 28733bbb8e48SRichard Henderson } 28743bbb8e48SRichard Henderson 28753bbb8e48SRichard Henderson nullify_over(ctx); 28763bbb8e48SRichard Henderson 28773bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 28783bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 28793bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 28803bbb8e48SRichard Henderson 28813bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 28823bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 28833bbb8e48SRichard Henderson 28843bbb8e48SRichard Henderson return nullify_end(ctx); 28853bbb8e48SRichard Henderson } 28863bbb8e48SRichard Henderson 28870843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 28880843563fSRichard Henderson { 28890843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 28900843563fSRichard Henderson } 28910843563fSRichard Henderson 28920843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 28930843563fSRichard Henderson { 28940843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 28950843563fSRichard Henderson } 28960843563fSRichard Henderson 28970843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 28980843563fSRichard Henderson { 28990843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 29000843563fSRichard Henderson } 29010843563fSRichard Henderson 29021b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 29031b3cb7c8SRichard Henderson { 29041b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 29051b3cb7c8SRichard Henderson } 29061b3cb7c8SRichard Henderson 2907151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 2908151f309bSRichard Henderson { 2909151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 2910151f309bSRichard Henderson } 2911151f309bSRichard Henderson 2912151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 2913151f309bSRichard Henderson { 2914151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 2915151f309bSRichard Henderson } 2916151f309bSRichard Henderson 2917151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 2918151f309bSRichard Henderson { 2919151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 2920151f309bSRichard Henderson } 2921151f309bSRichard Henderson 29223bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 29233bbb8e48SRichard Henderson { 29243bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 29253bbb8e48SRichard Henderson } 29263bbb8e48SRichard Henderson 29273bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 29283bbb8e48SRichard Henderson { 29293bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 29303bbb8e48SRichard Henderson } 29313bbb8e48SRichard Henderson 293210c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 293310c9e58dSRichard Henderson { 293410c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 293510c9e58dSRichard Henderson } 293610c9e58dSRichard Henderson 293710c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 293810c9e58dSRichard Henderson { 293910c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 294010c9e58dSRichard Henderson } 294110c9e58dSRichard Henderson 294210c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 294310c9e58dSRichard Henderson { 294410c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 294510c9e58dSRichard Henderson } 294610c9e58dSRichard Henderson 2947c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2948c2a7ee3fSRichard Henderson { 2949c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 2950c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2951c2a7ee3fSRichard Henderson 2952c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 2953c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 2954c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 2955c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2956c2a7ee3fSRichard Henderson } 2957c2a7ee3fSRichard Henderson 2958c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 2959c2a7ee3fSRichard Henderson { 2960c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 2961c2a7ee3fSRichard Henderson } 2962c2a7ee3fSRichard Henderson 2963c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2964c2a7ee3fSRichard Henderson { 2965c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 2966c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2967c2a7ee3fSRichard Henderson 2968c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 2969c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 2970c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 2971c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 2972c2a7ee3fSRichard Henderson } 2973c2a7ee3fSRichard Henderson 2974c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 2975c2a7ee3fSRichard Henderson { 2976c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 2977c2a7ee3fSRichard Henderson } 2978c2a7ee3fSRichard Henderson 2979c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2980c2a7ee3fSRichard Henderson { 2981c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2982c2a7ee3fSRichard Henderson 2983c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 2984c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 2985c2a7ee3fSRichard Henderson } 2986c2a7ee3fSRichard Henderson 2987c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 2988c2a7ee3fSRichard Henderson { 2989c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 2990c2a7ee3fSRichard Henderson } 2991c2a7ee3fSRichard Henderson 2992c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2993c2a7ee3fSRichard Henderson { 2994c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 2995c2a7ee3fSRichard Henderson } 2996c2a7ee3fSRichard Henderson 2997c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 2998c2a7ee3fSRichard Henderson { 2999c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 3000c2a7ee3fSRichard Henderson } 3001c2a7ee3fSRichard Henderson 30024e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 30034e7abdb1SRichard Henderson { 30044e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 30054e7abdb1SRichard Henderson 30064e7abdb1SRichard Henderson if (!ctx->is_pa20) { 30074e7abdb1SRichard Henderson return false; 30084e7abdb1SRichard Henderson } 30094e7abdb1SRichard Henderson 30104e7abdb1SRichard Henderson nullify_over(ctx); 30114e7abdb1SRichard Henderson 30124e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 30134e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 30144e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 30154e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 30164e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 30174e7abdb1SRichard Henderson 30184e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 30194e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 30204e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 30214e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 30224e7abdb1SRichard Henderson 30234e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 30244e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 30254e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 30264e7abdb1SRichard Henderson 30274e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 30284e7abdb1SRichard Henderson return nullify_end(ctx); 30294e7abdb1SRichard Henderson } 30304e7abdb1SRichard Henderson 30311cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 303296d6407fSRichard Henderson { 3033b5caa17cSRichard Henderson if (ctx->is_pa20) { 3034b5caa17cSRichard Henderson /* 3035b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3036b5caa17cSRichard Henderson * Any base modification still occurs. 3037b5caa17cSRichard Henderson */ 3038b5caa17cSRichard Henderson if (a->t == 0) { 3039b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3040b5caa17cSRichard Henderson } 3041b5caa17cSRichard Henderson } else if (a->size > MO_32) { 30420786a3b6SHelge Deller return gen_illegal(ctx); 3043c53e401eSRichard Henderson } 30441cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 30451cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 304696d6407fSRichard Henderson } 304796d6407fSRichard Henderson 30481cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 304996d6407fSRichard Henderson { 30501cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3051c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 30520786a3b6SHelge Deller return gen_illegal(ctx); 305396d6407fSRichard Henderson } 3054c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 30550786a3b6SHelge Deller } 305696d6407fSRichard Henderson 30571cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 305896d6407fSRichard Henderson { 3059b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3060a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 30616fd0c7bcSRichard Henderson TCGv_i64 addr; 306296d6407fSRichard Henderson 3063c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 306451416c4eSRichard Henderson return gen_illegal(ctx); 306551416c4eSRichard Henderson } 306651416c4eSRichard Henderson 306796d6407fSRichard Henderson nullify_over(ctx); 306896d6407fSRichard Henderson 30691cd012a5SRichard Henderson if (a->m) { 307086f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 307186f8d05fSRichard Henderson we see the result of the load. */ 3072aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 307396d6407fSRichard Henderson } else { 30741cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 307596d6407fSRichard Henderson } 307696d6407fSRichard Henderson 30771cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0, 30781cd012a5SRichard Henderson a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX); 3079b1af755cSRichard Henderson 3080b1af755cSRichard Henderson /* 3081b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3082b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3083b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3084b1af755cSRichard Henderson * 3085b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3086b1af755cSRichard Henderson * with the ,co completer. 3087b1af755cSRichard Henderson */ 3088b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3089b1af755cSRichard Henderson 3090a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3091b1af755cSRichard Henderson 30921cd012a5SRichard Henderson if (a->m) { 30931cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 309496d6407fSRichard Henderson } 30951cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 309696d6407fSRichard Henderson 309731234768SRichard Henderson return nullify_end(ctx); 309896d6407fSRichard Henderson } 309996d6407fSRichard Henderson 31001cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 310196d6407fSRichard Henderson { 31026fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31036fd0c7bcSRichard Henderson TCGv_i64 addr; 310496d6407fSRichard Henderson 310596d6407fSRichard Henderson nullify_over(ctx); 310696d6407fSRichard Henderson 31071cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 310886f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 31091cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 31101cd012a5SRichard Henderson if (a->a) { 3111f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3112ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3113f9f46db4SEmilio G. Cota } else { 3114ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3115f9f46db4SEmilio G. Cota } 3116f9f46db4SEmilio G. Cota } else { 3117f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3118ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 311996d6407fSRichard Henderson } else { 3120ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 312196d6407fSRichard Henderson } 3122f9f46db4SEmilio G. Cota } 31231cd012a5SRichard Henderson if (a->m) { 31246fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 31251cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 312696d6407fSRichard Henderson } 312796d6407fSRichard Henderson 312831234768SRichard Henderson return nullify_end(ctx); 312996d6407fSRichard Henderson } 313096d6407fSRichard Henderson 313125460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 313225460fc5SRichard Henderson { 31336fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31346fd0c7bcSRichard Henderson TCGv_i64 addr; 313525460fc5SRichard Henderson 313625460fc5SRichard Henderson if (!ctx->is_pa20) { 313725460fc5SRichard Henderson return false; 313825460fc5SRichard Henderson } 313925460fc5SRichard Henderson nullify_over(ctx); 314025460fc5SRichard Henderson 314125460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 314225460fc5SRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 314325460fc5SRichard Henderson val = load_gpr(ctx, a->r); 314425460fc5SRichard Henderson if (a->a) { 314525460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 314625460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 314725460fc5SRichard Henderson } else { 314825460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 314925460fc5SRichard Henderson } 315025460fc5SRichard Henderson } else { 315125460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 315225460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 315325460fc5SRichard Henderson } else { 315425460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 315525460fc5SRichard Henderson } 315625460fc5SRichard Henderson } 315725460fc5SRichard Henderson if (a->m) { 31586fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 315925460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 316025460fc5SRichard Henderson } 316125460fc5SRichard Henderson 316225460fc5SRichard Henderson return nullify_end(ctx); 316325460fc5SRichard Henderson } 316425460fc5SRichard Henderson 31651cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3166d0a851ccSRichard Henderson { 3167d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3168d0a851ccSRichard Henderson 3169d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3170d0a851ccSRichard Henderson ctx->mmu_idx = MMU_PHYS_IDX; 31711cd012a5SRichard Henderson trans_ld(ctx, a); 3172d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 317331234768SRichard Henderson return true; 3174d0a851ccSRichard Henderson } 3175d0a851ccSRichard Henderson 31761cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3177d0a851ccSRichard Henderson { 3178d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3179d0a851ccSRichard Henderson 3180d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3181d0a851ccSRichard Henderson ctx->mmu_idx = MMU_PHYS_IDX; 31821cd012a5SRichard Henderson trans_st(ctx, a); 3183d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 318431234768SRichard Henderson return true; 3185d0a851ccSRichard Henderson } 318695412a61SRichard Henderson 31870588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3188b2167459SRichard Henderson { 31896fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3190b2167459SRichard Henderson 31916fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 31920588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3193b2167459SRichard Henderson cond_free(&ctx->null_cond); 319431234768SRichard Henderson return true; 3195b2167459SRichard Henderson } 3196b2167459SRichard Henderson 31970588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3198b2167459SRichard Henderson { 31996fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 32006fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3201b2167459SRichard Henderson 32026fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3203b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3204b2167459SRichard Henderson cond_free(&ctx->null_cond); 320531234768SRichard Henderson return true; 3206b2167459SRichard Henderson } 3207b2167459SRichard Henderson 32080588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3209b2167459SRichard Henderson { 32106fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3211b2167459SRichard Henderson 3212b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3213d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 32140588e061SRichard Henderson if (a->b == 0) { 32156fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3216b2167459SRichard Henderson } else { 32176fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3218b2167459SRichard Henderson } 32190588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3220b2167459SRichard Henderson cond_free(&ctx->null_cond); 322131234768SRichard Henderson return true; 3222b2167459SRichard Henderson } 3223b2167459SRichard Henderson 32246fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3225e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 322698cd9ca7SRichard Henderson { 32276fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 322898cd9ca7SRichard Henderson DisasCond cond; 322998cd9ca7SRichard Henderson 323098cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3231aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 323298cd9ca7SRichard Henderson 32336fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 323498cd9ca7SRichard Henderson 3235f764718dSRichard Henderson sv = NULL; 3236b47a4a02SSven Schnelle if (cond_need_sv(c)) { 323798cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 323898cd9ca7SRichard Henderson } 323998cd9ca7SRichard Henderson 32404fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 324101afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 324298cd9ca7SRichard Henderson } 324398cd9ca7SRichard Henderson 324401afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 324598cd9ca7SRichard Henderson { 3246e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3247e9efd4bcSRichard Henderson return false; 3248e9efd4bcSRichard Henderson } 324901afb7beSRichard Henderson nullify_over(ctx); 3250e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3251e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 325201afb7beSRichard Henderson } 325301afb7beSRichard Henderson 325401afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 325501afb7beSRichard Henderson { 3256c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3257c65c3ee1SRichard Henderson return false; 3258c65c3ee1SRichard Henderson } 325901afb7beSRichard Henderson nullify_over(ctx); 32606fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3261c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 326201afb7beSRichard Henderson } 326301afb7beSRichard Henderson 32646fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 326501afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 326601afb7beSRichard Henderson { 32676fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 326898cd9ca7SRichard Henderson DisasCond cond; 3269bdcccc17SRichard Henderson bool d = false; 327098cd9ca7SRichard Henderson 3271f25d3160SRichard Henderson /* 3272f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3273f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3274f25d3160SRichard Henderson */ 3275f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3276f25d3160SRichard Henderson d = c >= 5; 3277f25d3160SRichard Henderson if (d) { 3278f25d3160SRichard Henderson c &= 3; 3279f25d3160SRichard Henderson } 3280f25d3160SRichard Henderson } 3281f25d3160SRichard Henderson 328298cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3283aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3284f764718dSRichard Henderson sv = NULL; 3285bdcccc17SRichard Henderson cb_cond = NULL; 328698cd9ca7SRichard Henderson 3287b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3288aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3289aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3290bdcccc17SRichard Henderson 32916fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 32926fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 32936fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 32946fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3295bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3296b47a4a02SSven Schnelle } else { 32976fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3298b47a4a02SSven Schnelle } 3299b47a4a02SSven Schnelle if (cond_need_sv(c)) { 330098cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 330198cd9ca7SRichard Henderson } 330298cd9ca7SRichard Henderson 3303a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 330443675d20SSven Schnelle save_gpr(ctx, r, dest); 330501afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 330698cd9ca7SRichard Henderson } 330798cd9ca7SRichard Henderson 330801afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 330998cd9ca7SRichard Henderson { 331001afb7beSRichard Henderson nullify_over(ctx); 331101afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 331201afb7beSRichard Henderson } 331301afb7beSRichard Henderson 331401afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 331501afb7beSRichard Henderson { 331601afb7beSRichard Henderson nullify_over(ctx); 33176fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 331801afb7beSRichard Henderson } 331901afb7beSRichard Henderson 332001afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 332101afb7beSRichard Henderson { 33226fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 332398cd9ca7SRichard Henderson DisasCond cond; 332498cd9ca7SRichard Henderson 332598cd9ca7SRichard Henderson nullify_over(ctx); 332698cd9ca7SRichard Henderson 3327aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 332801afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 332984e224d4SRichard Henderson if (cond_need_ext(ctx, a->d)) { 33301e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 33316fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 33326fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 33331e9ab9fbSRichard Henderson } else { 33346fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 33351e9ab9fbSRichard Henderson } 333698cd9ca7SRichard Henderson 33371e9ab9fbSRichard Henderson cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 333801afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 333998cd9ca7SRichard Henderson } 334098cd9ca7SRichard Henderson 334101afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 334298cd9ca7SRichard Henderson { 33436fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 334401afb7beSRichard Henderson DisasCond cond; 33451e9ab9fbSRichard Henderson int p; 334601afb7beSRichard Henderson 334701afb7beSRichard Henderson nullify_over(ctx); 334801afb7beSRichard Henderson 3349aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 335001afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 335184e224d4SRichard Henderson p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0); 33526fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, tcg_r, p); 335301afb7beSRichard Henderson 335401afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 335501afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 335601afb7beSRichard Henderson } 335701afb7beSRichard Henderson 335801afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 335901afb7beSRichard Henderson { 33606fd0c7bcSRichard Henderson TCGv_i64 dest; 336198cd9ca7SRichard Henderson DisasCond cond; 336298cd9ca7SRichard Henderson 336398cd9ca7SRichard Henderson nullify_over(ctx); 336498cd9ca7SRichard Henderson 336501afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 336601afb7beSRichard Henderson if (a->r1 == 0) { 33676fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 336898cd9ca7SRichard Henderson } else { 33696fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 337098cd9ca7SRichard Henderson } 337198cd9ca7SRichard Henderson 33724fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 33734fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 337401afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 337501afb7beSRichard Henderson } 337601afb7beSRichard Henderson 337701afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 337801afb7beSRichard Henderson { 33796fd0c7bcSRichard Henderson TCGv_i64 dest; 338001afb7beSRichard Henderson DisasCond cond; 338101afb7beSRichard Henderson 338201afb7beSRichard Henderson nullify_over(ctx); 338301afb7beSRichard Henderson 338401afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 33856fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 338601afb7beSRichard Henderson 33874fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 33884fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 338901afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 339098cd9ca7SRichard Henderson } 339198cd9ca7SRichard Henderson 3392f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 33930b1347d2SRichard Henderson { 33946fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 33950b1347d2SRichard Henderson 3396f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3397f7b775a9SRichard Henderson return false; 3398f7b775a9SRichard Henderson } 339930878590SRichard Henderson if (a->c) { 34000b1347d2SRichard Henderson nullify_over(ctx); 34010b1347d2SRichard Henderson } 34020b1347d2SRichard Henderson 340330878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3404f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 340530878590SRichard Henderson if (a->r1 == 0) { 3406f7b775a9SRichard Henderson if (a->d) { 34076fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3408f7b775a9SRichard Henderson } else { 3409aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3410f7b775a9SRichard Henderson 34116fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 34126fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 34136fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3414f7b775a9SRichard Henderson } 341530878590SRichard Henderson } else if (a->r1 == a->r2) { 3416f7b775a9SRichard Henderson if (a->d) { 34176fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3418f7b775a9SRichard Henderson } else { 34190b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3420e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3421e1d635e8SRichard Henderson 34226fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 34236fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3424f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3425e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 34266fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3427f7b775a9SRichard Henderson } 3428f7b775a9SRichard Henderson } else { 34296fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3430f7b775a9SRichard Henderson 3431f7b775a9SRichard Henderson if (a->d) { 3432aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3433aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3434f7b775a9SRichard Henderson 34356fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 34366fd0c7bcSRichard Henderson tcg_gen_shl_i64(t, src2, n); 34376fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 34386fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src1, cpu_sar); 34396fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 34400b1347d2SRichard Henderson } else { 34410b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 34420b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 34430b1347d2SRichard Henderson 34446fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3445967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3446967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 34470b1347d2SRichard Henderson } 3448f7b775a9SRichard Henderson } 344930878590SRichard Henderson save_gpr(ctx, a->t, dest); 34500b1347d2SRichard Henderson 34510b1347d2SRichard Henderson /* Install the new nullification. */ 34520b1347d2SRichard Henderson cond_free(&ctx->null_cond); 345330878590SRichard Henderson if (a->c) { 34544fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 34550b1347d2SRichard Henderson } 345631234768SRichard Henderson return nullify_end(ctx); 34570b1347d2SRichard Henderson } 34580b1347d2SRichard Henderson 3459f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 34600b1347d2SRichard Henderson { 3461f7b775a9SRichard Henderson unsigned width, sa; 34626fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 34630b1347d2SRichard Henderson 3464f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3465f7b775a9SRichard Henderson return false; 3466f7b775a9SRichard Henderson } 346730878590SRichard Henderson if (a->c) { 34680b1347d2SRichard Henderson nullify_over(ctx); 34690b1347d2SRichard Henderson } 34700b1347d2SRichard Henderson 3471f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3472f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3473f7b775a9SRichard Henderson 347430878590SRichard Henderson dest = dest_gpr(ctx, a->t); 347530878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 347605bfd4dbSRichard Henderson if (a->r1 == 0) { 34776fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3478c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 34796fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3480f7b775a9SRichard Henderson } else { 3481f7b775a9SRichard Henderson assert(!a->d); 3482f7b775a9SRichard Henderson if (a->r1 == a->r2) { 34830b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 34846fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 34850b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 34866fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 34870b1347d2SRichard Henderson } else { 3488967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3489967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 34900b1347d2SRichard Henderson } 3491f7b775a9SRichard Henderson } 349230878590SRichard Henderson save_gpr(ctx, a->t, dest); 34930b1347d2SRichard Henderson 34940b1347d2SRichard Henderson /* Install the new nullification. */ 34950b1347d2SRichard Henderson cond_free(&ctx->null_cond); 349630878590SRichard Henderson if (a->c) { 34974fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 34980b1347d2SRichard Henderson } 349931234768SRichard Henderson return nullify_end(ctx); 35000b1347d2SRichard Henderson } 35010b1347d2SRichard Henderson 3502bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 35030b1347d2SRichard Henderson { 3504bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 35056fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 35060b1347d2SRichard Henderson 3507bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3508bd792da3SRichard Henderson return false; 3509bd792da3SRichard Henderson } 351030878590SRichard Henderson if (a->c) { 35110b1347d2SRichard Henderson nullify_over(ctx); 35120b1347d2SRichard Henderson } 35130b1347d2SRichard Henderson 351430878590SRichard Henderson dest = dest_gpr(ctx, a->t); 351530878590SRichard Henderson src = load_gpr(ctx, a->r); 3516aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 35170b1347d2SRichard Henderson 35180b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 35196fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 35206fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3521d781cb77SRichard Henderson 352230878590SRichard Henderson if (a->se) { 3523bd792da3SRichard Henderson if (!a->d) { 35246fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3525bd792da3SRichard Henderson src = dest; 3526bd792da3SRichard Henderson } 35276fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 35286fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 35290b1347d2SRichard Henderson } else { 3530bd792da3SRichard Henderson if (!a->d) { 35316fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3532bd792da3SRichard Henderson src = dest; 3533bd792da3SRichard Henderson } 35346fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 35356fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 35360b1347d2SRichard Henderson } 353730878590SRichard Henderson save_gpr(ctx, a->t, dest); 35380b1347d2SRichard Henderson 35390b1347d2SRichard Henderson /* Install the new nullification. */ 35400b1347d2SRichard Henderson cond_free(&ctx->null_cond); 354130878590SRichard Henderson if (a->c) { 3542bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35430b1347d2SRichard Henderson } 354431234768SRichard Henderson return nullify_end(ctx); 35450b1347d2SRichard Henderson } 35460b1347d2SRichard Henderson 3547bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 35480b1347d2SRichard Henderson { 3549bd792da3SRichard Henderson unsigned len, cpos, width; 35506fd0c7bcSRichard Henderson TCGv_i64 dest, src; 35510b1347d2SRichard Henderson 3552bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3553bd792da3SRichard Henderson return false; 3554bd792da3SRichard Henderson } 355530878590SRichard Henderson if (a->c) { 35560b1347d2SRichard Henderson nullify_over(ctx); 35570b1347d2SRichard Henderson } 35580b1347d2SRichard Henderson 3559bd792da3SRichard Henderson len = a->len; 3560bd792da3SRichard Henderson width = a->d ? 64 : 32; 3561bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3562bd792da3SRichard Henderson if (cpos + len > width) { 3563bd792da3SRichard Henderson len = width - cpos; 3564bd792da3SRichard Henderson } 3565bd792da3SRichard Henderson 356630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 356730878590SRichard Henderson src = load_gpr(ctx, a->r); 356830878590SRichard Henderson if (a->se) { 35696fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 35700b1347d2SRichard Henderson } else { 35716fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 35720b1347d2SRichard Henderson } 357330878590SRichard Henderson save_gpr(ctx, a->t, dest); 35740b1347d2SRichard Henderson 35750b1347d2SRichard Henderson /* Install the new nullification. */ 35760b1347d2SRichard Henderson cond_free(&ctx->null_cond); 357730878590SRichard Henderson if (a->c) { 3578bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35790b1347d2SRichard Henderson } 358031234768SRichard Henderson return nullify_end(ctx); 35810b1347d2SRichard Henderson } 35820b1347d2SRichard Henderson 358372ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 35840b1347d2SRichard Henderson { 358572ae4f2bSRichard Henderson unsigned len, width; 3586c53e401eSRichard Henderson uint64_t mask0, mask1; 35876fd0c7bcSRichard Henderson TCGv_i64 dest; 35880b1347d2SRichard Henderson 358972ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 359072ae4f2bSRichard Henderson return false; 359172ae4f2bSRichard Henderson } 359230878590SRichard Henderson if (a->c) { 35930b1347d2SRichard Henderson nullify_over(ctx); 35940b1347d2SRichard Henderson } 359572ae4f2bSRichard Henderson 359672ae4f2bSRichard Henderson len = a->len; 359772ae4f2bSRichard Henderson width = a->d ? 64 : 32; 359872ae4f2bSRichard Henderson if (a->cpos + len > width) { 359972ae4f2bSRichard Henderson len = width - a->cpos; 36000b1347d2SRichard Henderson } 36010b1347d2SRichard Henderson 360230878590SRichard Henderson dest = dest_gpr(ctx, a->t); 360330878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 360430878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 36050b1347d2SRichard Henderson 360630878590SRichard Henderson if (a->nz) { 36076fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 36086fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 36096fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 36100b1347d2SRichard Henderson } else { 36116fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 36120b1347d2SRichard Henderson } 361330878590SRichard Henderson save_gpr(ctx, a->t, dest); 36140b1347d2SRichard Henderson 36150b1347d2SRichard Henderson /* Install the new nullification. */ 36160b1347d2SRichard Henderson cond_free(&ctx->null_cond); 361730878590SRichard Henderson if (a->c) { 361872ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36190b1347d2SRichard Henderson } 362031234768SRichard Henderson return nullify_end(ctx); 36210b1347d2SRichard Henderson } 36220b1347d2SRichard Henderson 362372ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 36240b1347d2SRichard Henderson { 362530878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 362672ae4f2bSRichard Henderson unsigned len, width; 36276fd0c7bcSRichard Henderson TCGv_i64 dest, val; 36280b1347d2SRichard Henderson 362972ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 363072ae4f2bSRichard Henderson return false; 363172ae4f2bSRichard Henderson } 363230878590SRichard Henderson if (a->c) { 36330b1347d2SRichard Henderson nullify_over(ctx); 36340b1347d2SRichard Henderson } 363572ae4f2bSRichard Henderson 363672ae4f2bSRichard Henderson len = a->len; 363772ae4f2bSRichard Henderson width = a->d ? 64 : 32; 363872ae4f2bSRichard Henderson if (a->cpos + len > width) { 363972ae4f2bSRichard Henderson len = width - a->cpos; 36400b1347d2SRichard Henderson } 36410b1347d2SRichard Henderson 364230878590SRichard Henderson dest = dest_gpr(ctx, a->t); 364330878590SRichard Henderson val = load_gpr(ctx, a->r); 36440b1347d2SRichard Henderson if (rs == 0) { 36456fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 36460b1347d2SRichard Henderson } else { 36476fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 36480b1347d2SRichard Henderson } 364930878590SRichard Henderson save_gpr(ctx, a->t, dest); 36500b1347d2SRichard Henderson 36510b1347d2SRichard Henderson /* Install the new nullification. */ 36520b1347d2SRichard Henderson cond_free(&ctx->null_cond); 365330878590SRichard Henderson if (a->c) { 365472ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36550b1347d2SRichard Henderson } 365631234768SRichard Henderson return nullify_end(ctx); 36570b1347d2SRichard Henderson } 36580b1347d2SRichard Henderson 365972ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 36606fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 36610b1347d2SRichard Henderson { 36620b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 366372ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 36646fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3665c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 36660b1347d2SRichard Henderson 36670b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3668aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3669aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 36700b1347d2SRichard Henderson 36710b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 36726fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 36736fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 36740b1347d2SRichard Henderson 3675aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 36766fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 36776fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 36780b1347d2SRichard Henderson if (rs) { 36796fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 36806fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 36816fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 36826fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 36830b1347d2SRichard Henderson } else { 36846fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 36850b1347d2SRichard Henderson } 36860b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 36870b1347d2SRichard Henderson 36880b1347d2SRichard Henderson /* Install the new nullification. */ 36890b1347d2SRichard Henderson cond_free(&ctx->null_cond); 36900b1347d2SRichard Henderson if (c) { 369172ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 36920b1347d2SRichard Henderson } 369331234768SRichard Henderson return nullify_end(ctx); 36940b1347d2SRichard Henderson } 36950b1347d2SRichard Henderson 369672ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 369730878590SRichard Henderson { 369872ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 369972ae4f2bSRichard Henderson return false; 370072ae4f2bSRichard Henderson } 3701a6deecceSSven Schnelle if (a->c) { 3702a6deecceSSven Schnelle nullify_over(ctx); 3703a6deecceSSven Schnelle } 370472ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 370572ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 370630878590SRichard Henderson } 370730878590SRichard Henderson 370872ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 370930878590SRichard Henderson { 371072ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 371172ae4f2bSRichard Henderson return false; 371272ae4f2bSRichard Henderson } 3713a6deecceSSven Schnelle if (a->c) { 3714a6deecceSSven Schnelle nullify_over(ctx); 3715a6deecceSSven Schnelle } 371672ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 37176fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 371830878590SRichard Henderson } 37190b1347d2SRichard Henderson 37208340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 372198cd9ca7SRichard Henderson { 37226fd0c7bcSRichard Henderson TCGv_i64 tmp; 372398cd9ca7SRichard Henderson 3724c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 372598cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 372698cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 372798cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 372898cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 372998cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 373098cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 373198cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 373298cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 37338340f534SRichard Henderson if (a->b == 0) { 37348340f534SRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 373598cd9ca7SRichard Henderson } 3736c301f34eSRichard Henderson #else 3737c301f34eSRichard Henderson nullify_over(ctx); 3738660eefe1SRichard Henderson #endif 3739660eefe1SRichard Henderson 3740aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37416fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp); 3742660eefe1SRichard Henderson tmp = do_ibranch_priv(ctx, tmp); 3743c301f34eSRichard Henderson 3744c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 37458340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3746c301f34eSRichard Henderson #else 3747c301f34eSRichard Henderson TCGv_i64 new_spc = tcg_temp_new_i64(); 3748c301f34eSRichard Henderson 37498340f534SRichard Henderson load_spr(ctx, new_spc, a->sp); 37508340f534SRichard Henderson if (a->l) { 3751741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); 3752c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); 3753c301f34eSRichard Henderson } 37548340f534SRichard Henderson if (a->n && use_nullify_skip(ctx)) { 3755a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 37566fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 3757a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3758c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, new_spc); 3759c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); 3760c301f34eSRichard Henderson } else { 3761741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3762c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3763c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3764c301f34eSRichard Henderson } 3765a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3766c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, new_spc); 37678340f534SRichard Henderson nullify_set(ctx, a->n); 3768c301f34eSRichard Henderson } 3769c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 377031234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 377131234768SRichard Henderson return nullify_end(ctx); 3772c301f34eSRichard Henderson #endif 377398cd9ca7SRichard Henderson } 377498cd9ca7SRichard Henderson 37758340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 377698cd9ca7SRichard Henderson { 37778340f534SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n); 377898cd9ca7SRichard Henderson } 377998cd9ca7SRichard Henderson 37808340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 378143e05652SRichard Henderson { 3782c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, a->disp); 378343e05652SRichard Henderson 37846e5f5300SSven Schnelle nullify_over(ctx); 37856e5f5300SSven Schnelle 378643e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 378743e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 378843e05652SRichard Henderson * expensive to track. Real hardware will trap for 378943e05652SRichard Henderson * b gateway 379043e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 379143e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 379243e05652SRichard Henderson * diagnose the security hole 379343e05652SRichard Henderson * b gateway 379443e05652SRichard Henderson * b evil 379543e05652SRichard Henderson * in which instructions at evil would run with increased privs. 379643e05652SRichard Henderson */ 379743e05652SRichard Henderson if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) { 379843e05652SRichard Henderson return gen_illegal(ctx); 379943e05652SRichard Henderson } 380043e05652SRichard Henderson 380143e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 380243e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 3803b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(ctx->cs); 380443e05652SRichard Henderson int type = hppa_artype_for_page(env, ctx->base.pc_next); 380543e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 380643e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 380743e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 380843e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 380943e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 381043e05652SRichard Henderson if (type < 0) { 381131234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 381231234768SRichard Henderson return true; 381343e05652SRichard Henderson } 381443e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 381543e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 381643e05652SRichard Henderson dest = deposit32(dest, 0, 2, type - 4); 381743e05652SRichard Henderson } 381843e05652SRichard Henderson } else { 381943e05652SRichard Henderson dest &= -4; /* priv = 0 */ 382043e05652SRichard Henderson } 382143e05652SRichard Henderson #endif 382243e05652SRichard Henderson 38236e5f5300SSven Schnelle if (a->l) { 38246fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 38256e5f5300SSven Schnelle if (ctx->privilege < 3) { 38266fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 38276e5f5300SSven Schnelle } 38286fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 38296e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 38306e5f5300SSven Schnelle } 38316e5f5300SSven Schnelle 38326e5f5300SSven Schnelle return do_dbranch(ctx, dest, 0, a->n); 383343e05652SRichard Henderson } 383443e05652SRichard Henderson 38358340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 383698cd9ca7SRichard Henderson { 3837b35aec85SRichard Henderson if (a->x) { 3838aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 38396fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3); 38406fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8); 3841660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 38428340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3843b35aec85SRichard Henderson } else { 3844b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 3845b35aec85SRichard Henderson return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n); 3846b35aec85SRichard Henderson } 384798cd9ca7SRichard Henderson } 384898cd9ca7SRichard Henderson 38498340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 385098cd9ca7SRichard Henderson { 38516fd0c7bcSRichard Henderson TCGv_i64 dest; 385298cd9ca7SRichard Henderson 38538340f534SRichard Henderson if (a->x == 0) { 38548340f534SRichard Henderson dest = load_gpr(ctx, a->b); 385598cd9ca7SRichard Henderson } else { 3856aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 38576fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 38586fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 385998cd9ca7SRichard Henderson } 3860660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 38618340f534SRichard Henderson return do_ibranch(ctx, dest, 0, a->n); 386298cd9ca7SRichard Henderson } 386398cd9ca7SRichard Henderson 38648340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 386598cd9ca7SRichard Henderson { 38666fd0c7bcSRichard Henderson TCGv_i64 dest; 386798cd9ca7SRichard Henderson 3868c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 38698340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 38708340f534SRichard Henderson return do_ibranch(ctx, dest, a->l, a->n); 3871c301f34eSRichard Henderson #else 3872c301f34eSRichard Henderson nullify_over(ctx); 38738340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3874c301f34eSRichard Henderson 3875741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3876c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3877c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3878c301f34eSRichard Henderson } 3879741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest); 3880c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); 38818340f534SRichard Henderson if (a->l) { 3882741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var); 3883c301f34eSRichard Henderson } 38848340f534SRichard Henderson nullify_set(ctx, a->n); 3885c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 388631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 388731234768SRichard Henderson return nullify_end(ctx); 3888c301f34eSRichard Henderson #endif 388998cd9ca7SRichard Henderson } 389098cd9ca7SRichard Henderson 3891a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 3892a8966ba7SRichard Henderson { 3893a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 3894a8966ba7SRichard Henderson return ctx->is_pa20; 3895a8966ba7SRichard Henderson } 3896a8966ba7SRichard Henderson 38971ca74648SRichard Henderson /* 38981ca74648SRichard Henderson * Float class 0 38991ca74648SRichard Henderson */ 3900ebe9383cSRichard Henderson 39011ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3902ebe9383cSRichard Henderson { 3903ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3904ebe9383cSRichard Henderson } 3905ebe9383cSRichard Henderson 390659f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 390759f8c04bSHelge Deller { 3908a300dad3SRichard Henderson uint64_t ret; 3909a300dad3SRichard Henderson 3910c53e401eSRichard Henderson if (ctx->is_pa20) { 3911a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 3912a300dad3SRichard Henderson } else { 3913a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 3914a300dad3SRichard Henderson } 3915a300dad3SRichard Henderson 391659f8c04bSHelge Deller nullify_over(ctx); 3917a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 391859f8c04bSHelge Deller return nullify_end(ctx); 391959f8c04bSHelge Deller } 392059f8c04bSHelge Deller 39211ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 39221ca74648SRichard Henderson { 39231ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 39241ca74648SRichard Henderson } 39251ca74648SRichard Henderson 3926ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3927ebe9383cSRichard Henderson { 3928ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 3929ebe9383cSRichard Henderson } 3930ebe9383cSRichard Henderson 39311ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 39321ca74648SRichard Henderson { 39331ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 39341ca74648SRichard Henderson } 39351ca74648SRichard Henderson 39361ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3937ebe9383cSRichard Henderson { 3938ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 3939ebe9383cSRichard Henderson } 3940ebe9383cSRichard Henderson 39411ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 39421ca74648SRichard Henderson { 39431ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 39441ca74648SRichard Henderson } 39451ca74648SRichard Henderson 3946ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3947ebe9383cSRichard Henderson { 3948ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 3949ebe9383cSRichard Henderson } 3950ebe9383cSRichard Henderson 39511ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 39521ca74648SRichard Henderson { 39531ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 39541ca74648SRichard Henderson } 39551ca74648SRichard Henderson 39561ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 39571ca74648SRichard Henderson { 39581ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 39591ca74648SRichard Henderson } 39601ca74648SRichard Henderson 39611ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 39621ca74648SRichard Henderson { 39631ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 39641ca74648SRichard Henderson } 39651ca74648SRichard Henderson 39661ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 39671ca74648SRichard Henderson { 39681ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 39691ca74648SRichard Henderson } 39701ca74648SRichard Henderson 39711ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 39721ca74648SRichard Henderson { 39731ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 39741ca74648SRichard Henderson } 39751ca74648SRichard Henderson 39761ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3977ebe9383cSRichard Henderson { 3978ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 3979ebe9383cSRichard Henderson } 3980ebe9383cSRichard Henderson 39811ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 39821ca74648SRichard Henderson { 39831ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 39841ca74648SRichard Henderson } 39851ca74648SRichard Henderson 3986ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3987ebe9383cSRichard Henderson { 3988ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 3989ebe9383cSRichard Henderson } 3990ebe9383cSRichard Henderson 39911ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 39921ca74648SRichard Henderson { 39931ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 39941ca74648SRichard Henderson } 39951ca74648SRichard Henderson 39961ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3997ebe9383cSRichard Henderson { 3998ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 3999ebe9383cSRichard Henderson } 4000ebe9383cSRichard Henderson 40011ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 40021ca74648SRichard Henderson { 40031ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 40041ca74648SRichard Henderson } 40051ca74648SRichard Henderson 4006ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4007ebe9383cSRichard Henderson { 4008ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4009ebe9383cSRichard Henderson } 4010ebe9383cSRichard Henderson 40111ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 40121ca74648SRichard Henderson { 40131ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 40141ca74648SRichard Henderson } 40151ca74648SRichard Henderson 40161ca74648SRichard Henderson /* 40171ca74648SRichard Henderson * Float class 1 40181ca74648SRichard Henderson */ 40191ca74648SRichard Henderson 40201ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 40211ca74648SRichard Henderson { 40221ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 40231ca74648SRichard Henderson } 40241ca74648SRichard Henderson 40251ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 40261ca74648SRichard Henderson { 40271ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 40281ca74648SRichard Henderson } 40291ca74648SRichard Henderson 40301ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 40311ca74648SRichard Henderson { 40321ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 40331ca74648SRichard Henderson } 40341ca74648SRichard Henderson 40351ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 40361ca74648SRichard Henderson { 40371ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 40381ca74648SRichard Henderson } 40391ca74648SRichard Henderson 40401ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 40411ca74648SRichard Henderson { 40421ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 40431ca74648SRichard Henderson } 40441ca74648SRichard Henderson 40451ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 40461ca74648SRichard Henderson { 40471ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 40481ca74648SRichard Henderson } 40491ca74648SRichard Henderson 40501ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 40511ca74648SRichard Henderson { 40521ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 40531ca74648SRichard Henderson } 40541ca74648SRichard Henderson 40551ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 40561ca74648SRichard Henderson { 40571ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 40581ca74648SRichard Henderson } 40591ca74648SRichard Henderson 40601ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 40611ca74648SRichard Henderson { 40621ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 40631ca74648SRichard Henderson } 40641ca74648SRichard Henderson 40651ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 40661ca74648SRichard Henderson { 40671ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 40681ca74648SRichard Henderson } 40691ca74648SRichard Henderson 40701ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 40711ca74648SRichard Henderson { 40721ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 40731ca74648SRichard Henderson } 40741ca74648SRichard Henderson 40751ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 40761ca74648SRichard Henderson { 40771ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 40781ca74648SRichard Henderson } 40791ca74648SRichard Henderson 40801ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 40811ca74648SRichard Henderson { 40821ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 40831ca74648SRichard Henderson } 40841ca74648SRichard Henderson 40851ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 40861ca74648SRichard Henderson { 40871ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 40881ca74648SRichard Henderson } 40891ca74648SRichard Henderson 40901ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 40911ca74648SRichard Henderson { 40921ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 40931ca74648SRichard Henderson } 40941ca74648SRichard Henderson 40951ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 40961ca74648SRichard Henderson { 40971ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 40981ca74648SRichard Henderson } 40991ca74648SRichard Henderson 41001ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 41011ca74648SRichard Henderson { 41021ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 41031ca74648SRichard Henderson } 41041ca74648SRichard Henderson 41051ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 41061ca74648SRichard Henderson { 41071ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 41081ca74648SRichard Henderson } 41091ca74648SRichard Henderson 41101ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 41111ca74648SRichard Henderson { 41121ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 41131ca74648SRichard Henderson } 41141ca74648SRichard Henderson 41151ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 41161ca74648SRichard Henderson { 41171ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 41181ca74648SRichard Henderson } 41191ca74648SRichard Henderson 41201ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 41211ca74648SRichard Henderson { 41221ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 41231ca74648SRichard Henderson } 41241ca74648SRichard Henderson 41251ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 41261ca74648SRichard Henderson { 41271ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 41281ca74648SRichard Henderson } 41291ca74648SRichard Henderson 41301ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 41311ca74648SRichard Henderson { 41321ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 41331ca74648SRichard Henderson } 41341ca74648SRichard Henderson 41351ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 41361ca74648SRichard Henderson { 41371ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 41381ca74648SRichard Henderson } 41391ca74648SRichard Henderson 41401ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 41411ca74648SRichard Henderson { 41421ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 41431ca74648SRichard Henderson } 41441ca74648SRichard Henderson 41451ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 41461ca74648SRichard Henderson { 41471ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 41481ca74648SRichard Henderson } 41491ca74648SRichard Henderson 41501ca74648SRichard Henderson /* 41511ca74648SRichard Henderson * Float class 2 41521ca74648SRichard Henderson */ 41531ca74648SRichard Henderson 41541ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4155ebe9383cSRichard Henderson { 4156ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4157ebe9383cSRichard Henderson 4158ebe9383cSRichard Henderson nullify_over(ctx); 4159ebe9383cSRichard Henderson 41601ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 41611ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 416229dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 416329dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4164ebe9383cSRichard Henderson 4165ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4166ebe9383cSRichard Henderson 41671ca74648SRichard Henderson return nullify_end(ctx); 4168ebe9383cSRichard Henderson } 4169ebe9383cSRichard Henderson 41701ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4171ebe9383cSRichard Henderson { 4172ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4173ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4174ebe9383cSRichard Henderson 4175ebe9383cSRichard Henderson nullify_over(ctx); 4176ebe9383cSRichard Henderson 41771ca74648SRichard Henderson ta = load_frd0(a->r1); 41781ca74648SRichard Henderson tb = load_frd0(a->r2); 417929dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 418029dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4181ebe9383cSRichard Henderson 4182ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4183ebe9383cSRichard Henderson 418431234768SRichard Henderson return nullify_end(ctx); 4185ebe9383cSRichard Henderson } 4186ebe9383cSRichard Henderson 41871ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4188ebe9383cSRichard Henderson { 41896fd0c7bcSRichard Henderson TCGv_i64 t; 4190ebe9383cSRichard Henderson 4191ebe9383cSRichard Henderson nullify_over(ctx); 4192ebe9383cSRichard Henderson 4193aac0f603SRichard Henderson t = tcg_temp_new_i64(); 41946fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4195ebe9383cSRichard Henderson 41961ca74648SRichard Henderson if (a->y == 1) { 4197ebe9383cSRichard Henderson int mask; 4198ebe9383cSRichard Henderson bool inv = false; 4199ebe9383cSRichard Henderson 42001ca74648SRichard Henderson switch (a->c) { 4201ebe9383cSRichard Henderson case 0: /* simple */ 42026fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 4203ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4204ebe9383cSRichard Henderson goto done; 4205ebe9383cSRichard Henderson case 2: /* rej */ 4206ebe9383cSRichard Henderson inv = true; 4207ebe9383cSRichard Henderson /* fallthru */ 4208ebe9383cSRichard Henderson case 1: /* acc */ 4209ebe9383cSRichard Henderson mask = 0x43ff800; 4210ebe9383cSRichard Henderson break; 4211ebe9383cSRichard Henderson case 6: /* rej8 */ 4212ebe9383cSRichard Henderson inv = true; 4213ebe9383cSRichard Henderson /* fallthru */ 4214ebe9383cSRichard Henderson case 5: /* acc8 */ 4215ebe9383cSRichard Henderson mask = 0x43f8000; 4216ebe9383cSRichard Henderson break; 4217ebe9383cSRichard Henderson case 9: /* acc6 */ 4218ebe9383cSRichard Henderson mask = 0x43e0000; 4219ebe9383cSRichard Henderson break; 4220ebe9383cSRichard Henderson case 13: /* acc4 */ 4221ebe9383cSRichard Henderson mask = 0x4380000; 4222ebe9383cSRichard Henderson break; 4223ebe9383cSRichard Henderson case 17: /* acc2 */ 4224ebe9383cSRichard Henderson mask = 0x4200000; 4225ebe9383cSRichard Henderson break; 4226ebe9383cSRichard Henderson default: 42271ca74648SRichard Henderson gen_illegal(ctx); 42281ca74648SRichard Henderson return true; 4229ebe9383cSRichard Henderson } 4230ebe9383cSRichard Henderson if (inv) { 42316fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 42326fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 4233ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 4234ebe9383cSRichard Henderson } else { 42356fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 4236ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 4237ebe9383cSRichard Henderson } 42381ca74648SRichard Henderson } else { 42391ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 42401ca74648SRichard Henderson 42416fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 42421ca74648SRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 42431ca74648SRichard Henderson } 42441ca74648SRichard Henderson 4245ebe9383cSRichard Henderson done: 424631234768SRichard Henderson return nullify_end(ctx); 4247ebe9383cSRichard Henderson } 4248ebe9383cSRichard Henderson 42491ca74648SRichard Henderson /* 42501ca74648SRichard Henderson * Float class 2 42511ca74648SRichard Henderson */ 42521ca74648SRichard Henderson 42531ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4254ebe9383cSRichard Henderson { 42551ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 42561ca74648SRichard Henderson } 42571ca74648SRichard Henderson 42581ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 42591ca74648SRichard Henderson { 42601ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 42611ca74648SRichard Henderson } 42621ca74648SRichard Henderson 42631ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 42641ca74648SRichard Henderson { 42651ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 42661ca74648SRichard Henderson } 42671ca74648SRichard Henderson 42681ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 42691ca74648SRichard Henderson { 42701ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 42711ca74648SRichard Henderson } 42721ca74648SRichard Henderson 42731ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 42741ca74648SRichard Henderson { 42751ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 42761ca74648SRichard Henderson } 42771ca74648SRichard Henderson 42781ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 42791ca74648SRichard Henderson { 42801ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 42811ca74648SRichard Henderson } 42821ca74648SRichard Henderson 42831ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 42841ca74648SRichard Henderson { 42851ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 42861ca74648SRichard Henderson } 42871ca74648SRichard Henderson 42881ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 42891ca74648SRichard Henderson { 42901ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 42911ca74648SRichard Henderson } 42921ca74648SRichard Henderson 42931ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 42941ca74648SRichard Henderson { 42951ca74648SRichard Henderson TCGv_i64 x, y; 4296ebe9383cSRichard Henderson 4297ebe9383cSRichard Henderson nullify_over(ctx); 4298ebe9383cSRichard Henderson 42991ca74648SRichard Henderson x = load_frw0_i64(a->r1); 43001ca74648SRichard Henderson y = load_frw0_i64(a->r2); 43011ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 43021ca74648SRichard Henderson save_frd(a->t, x); 4303ebe9383cSRichard Henderson 430431234768SRichard Henderson return nullify_end(ctx); 4305ebe9383cSRichard Henderson } 4306ebe9383cSRichard Henderson 4307ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4308ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4309ebe9383cSRichard Henderson { 4310ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4311ebe9383cSRichard Henderson } 4312ebe9383cSRichard Henderson 4313b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4314ebe9383cSRichard Henderson { 4315b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4316b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4317b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4318b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4319b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4320ebe9383cSRichard Henderson 4321ebe9383cSRichard Henderson nullify_over(ctx); 4322ebe9383cSRichard Henderson 4323ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4324ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4325ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4326ebe9383cSRichard Henderson 432731234768SRichard Henderson return nullify_end(ctx); 4328ebe9383cSRichard Henderson } 4329ebe9383cSRichard Henderson 4330b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4331b1e2af57SRichard Henderson { 4332b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4333b1e2af57SRichard Henderson } 4334b1e2af57SRichard Henderson 4335b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4336b1e2af57SRichard Henderson { 4337b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4338b1e2af57SRichard Henderson } 4339b1e2af57SRichard Henderson 4340b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4341b1e2af57SRichard Henderson { 4342b1e2af57SRichard Henderson nullify_over(ctx); 4343b1e2af57SRichard Henderson 4344b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4345b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4346b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4347b1e2af57SRichard Henderson 4348b1e2af57SRichard Henderson return nullify_end(ctx); 4349b1e2af57SRichard Henderson } 4350b1e2af57SRichard Henderson 4351b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4352b1e2af57SRichard Henderson { 4353b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4354b1e2af57SRichard Henderson } 4355b1e2af57SRichard Henderson 4356b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4357b1e2af57SRichard Henderson { 4358b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4359b1e2af57SRichard Henderson } 4360b1e2af57SRichard Henderson 4361c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4362ebe9383cSRichard Henderson { 4363c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4364ebe9383cSRichard Henderson 4365ebe9383cSRichard Henderson nullify_over(ctx); 4366c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4367c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4368c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4369ebe9383cSRichard Henderson 4370c3bad4f8SRichard Henderson if (a->neg) { 4371ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4372ebe9383cSRichard Henderson } else { 4373ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4374ebe9383cSRichard Henderson } 4375ebe9383cSRichard Henderson 4376c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 437731234768SRichard Henderson return nullify_end(ctx); 4378ebe9383cSRichard Henderson } 4379ebe9383cSRichard Henderson 4380c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4381ebe9383cSRichard Henderson { 4382c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4383ebe9383cSRichard Henderson 4384ebe9383cSRichard Henderson nullify_over(ctx); 4385c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4386c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4387c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4388ebe9383cSRichard Henderson 4389c3bad4f8SRichard Henderson if (a->neg) { 4390ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4391ebe9383cSRichard Henderson } else { 4392ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4393ebe9383cSRichard Henderson } 4394ebe9383cSRichard Henderson 4395c3bad4f8SRichard Henderson save_frd(a->t, x); 439631234768SRichard Henderson return nullify_end(ctx); 4397ebe9383cSRichard Henderson } 4398ebe9383cSRichard Henderson 439915da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a) 440015da177bSSven Schnelle { 4401cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4402cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4403cf6b28d4SHelge Deller if (a->i == 0x100) { 4404cf6b28d4SHelge Deller /* emulate PDC BTLB, called by SeaBIOS-hppa */ 4405ad75a51eSRichard Henderson nullify_over(ctx); 4406ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4407cf6b28d4SHelge Deller return nullify_end(ctx); 440815da177bSSven Schnelle } 4409ad75a51eSRichard Henderson #endif 4410ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4411ad75a51eSRichard Henderson return true; 4412ad75a51eSRichard Henderson } 441315da177bSSven Schnelle 4414b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 441561766fe9SRichard Henderson { 441651b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4417f764718dSRichard Henderson int bound; 441861766fe9SRichard Henderson 441951b061fbSRichard Henderson ctx->cs = cs; 4420494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4421bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 44223d68ee7bSRichard Henderson 44233d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4424c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 44253d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 4426c01e5dfbSHelge Deller ctx->iaoq_f = ctx->base.pc_first | ctx->privilege; 4427c01e5dfbSHelge Deller ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege; 4428217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4429c301f34eSRichard Henderson #else 4430494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4431bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4432bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4433bb67ec32SRichard Henderson : MMU_PHYS_IDX); 44343d68ee7bSRichard Henderson 4435c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4436c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4437c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4438c301f34eSRichard Henderson int32_t diff = cs_base; 4439c301f34eSRichard Henderson 4440c301f34eSRichard Henderson ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4441c301f34eSRichard Henderson ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); 4442c301f34eSRichard Henderson #endif 444351b061fbSRichard Henderson ctx->iaoq_n = -1; 4444f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 444561766fe9SRichard Henderson 4446a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4447a4db4a78SRichard Henderson 44483d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 44493d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4450b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 445161766fe9SRichard Henderson } 445261766fe9SRichard Henderson 445351b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 445451b061fbSRichard Henderson { 445551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 445661766fe9SRichard Henderson 44573d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 445851b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 445951b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4460494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 446151b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 446251b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4463129e9cc3SRichard Henderson } 446451b061fbSRichard Henderson ctx->null_lab = NULL; 446561766fe9SRichard Henderson } 446661766fe9SRichard Henderson 446751b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 446851b061fbSRichard Henderson { 446951b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 447051b061fbSRichard Henderson 4471*f5b5c857SRichard Henderson tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0); 4472*f5b5c857SRichard Henderson ctx->insn_start = tcg_last_op(); 447351b061fbSRichard Henderson } 447451b061fbSRichard Henderson 447551b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 447651b061fbSRichard Henderson { 447751b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4478b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 447951b061fbSRichard Henderson DisasJumpType ret; 448051b061fbSRichard Henderson 448151b061fbSRichard Henderson /* Execute one insn. */ 4482ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4483c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 448431234768SRichard Henderson do_page_zero(ctx); 448531234768SRichard Henderson ret = ctx->base.is_jmp; 4486869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4487ba1d0b44SRichard Henderson } else 4488ba1d0b44SRichard Henderson #endif 4489ba1d0b44SRichard Henderson { 449061766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 449161766fe9SRichard Henderson the page permissions for execute. */ 44924e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 449361766fe9SRichard Henderson 449461766fe9SRichard Henderson /* Set up the IA queue for the next insn. 449561766fe9SRichard Henderson This will be overwritten by a branch. */ 449651b061fbSRichard Henderson if (ctx->iaoq_b == -1) { 449751b061fbSRichard Henderson ctx->iaoq_n = -1; 4498aac0f603SRichard Henderson ctx->iaoq_n_var = tcg_temp_new_i64(); 44996fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 450061766fe9SRichard Henderson } else { 450151b061fbSRichard Henderson ctx->iaoq_n = ctx->iaoq_b + 4; 4502f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 450361766fe9SRichard Henderson } 450461766fe9SRichard Henderson 450551b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 450651b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4507869051eaSRichard Henderson ret = DISAS_NEXT; 4508129e9cc3SRichard Henderson } else { 45091a19da0dSRichard Henderson ctx->insn = insn; 451031274b46SRichard Henderson if (!decode(ctx, insn)) { 451131274b46SRichard Henderson gen_illegal(ctx); 451231274b46SRichard Henderson } 451331234768SRichard Henderson ret = ctx->base.is_jmp; 451451b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4515129e9cc3SRichard Henderson } 451661766fe9SRichard Henderson } 451761766fe9SRichard Henderson 45183d68ee7bSRichard Henderson /* Advance the insn queue. Note that this check also detects 45193d68ee7bSRichard Henderson a priority change within the instruction queue. */ 452051b061fbSRichard Henderson if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 4521c301f34eSRichard Henderson if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 4522c301f34eSRichard Henderson && use_goto_tb(ctx, ctx->iaoq_b) 4523c301f34eSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4524c301f34eSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 452551b061fbSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 452651b061fbSRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 452731234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_NORETURN; 4528129e9cc3SRichard Henderson } else { 452931234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE; 453061766fe9SRichard Henderson } 4531129e9cc3SRichard Henderson } 453251b061fbSRichard Henderson ctx->iaoq_f = ctx->iaoq_b; 453351b061fbSRichard Henderson ctx->iaoq_b = ctx->iaoq_n; 4534c301f34eSRichard Henderson ctx->base.pc_next += 4; 453561766fe9SRichard Henderson 4536c5d0aec2SRichard Henderson switch (ret) { 4537c5d0aec2SRichard Henderson case DISAS_NORETURN: 4538c5d0aec2SRichard Henderson case DISAS_IAQ_N_UPDATED: 4539c5d0aec2SRichard Henderson break; 4540c5d0aec2SRichard Henderson 4541c5d0aec2SRichard Henderson case DISAS_NEXT: 4542c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE: 4543c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 454451b061fbSRichard Henderson if (ctx->iaoq_f == -1) { 4545a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b); 4546741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 4547c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY 4548c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 4549c301f34eSRichard Henderson #endif 455051b061fbSRichard Henderson nullify_save(ctx); 4551c5d0aec2SRichard Henderson ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT 4552c5d0aec2SRichard Henderson ? DISAS_EXIT 4553c5d0aec2SRichard Henderson : DISAS_IAQ_N_UPDATED); 455451b061fbSRichard Henderson } else if (ctx->iaoq_b == -1) { 4555a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var); 455661766fe9SRichard Henderson } 4557c5d0aec2SRichard Henderson break; 4558c5d0aec2SRichard Henderson 4559c5d0aec2SRichard Henderson default: 4560c5d0aec2SRichard Henderson g_assert_not_reached(); 4561c5d0aec2SRichard Henderson } 456261766fe9SRichard Henderson } 456361766fe9SRichard Henderson 456451b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 456551b061fbSRichard Henderson { 456651b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4567e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 456851b061fbSRichard Henderson 4569e1b5a5edSRichard Henderson switch (is_jmp) { 4570869051eaSRichard Henderson case DISAS_NORETURN: 457161766fe9SRichard Henderson break; 457251b061fbSRichard Henderson case DISAS_TOO_MANY: 4573869051eaSRichard Henderson case DISAS_IAQ_N_STALE: 4574e1b5a5edSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4575741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 4576741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 457751b061fbSRichard Henderson nullify_save(ctx); 457861766fe9SRichard Henderson /* FALLTHRU */ 4579869051eaSRichard Henderson case DISAS_IAQ_N_UPDATED: 45808532a14eSRichard Henderson if (is_jmp != DISAS_IAQ_N_STALE_EXIT) { 45817f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 45828532a14eSRichard Henderson break; 458361766fe9SRichard Henderson } 4584c5d0aec2SRichard Henderson /* FALLTHRU */ 4585c5d0aec2SRichard Henderson case DISAS_EXIT: 4586c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 458761766fe9SRichard Henderson break; 458861766fe9SRichard Henderson default: 458951b061fbSRichard Henderson g_assert_not_reached(); 459061766fe9SRichard Henderson } 459151b061fbSRichard Henderson } 459261766fe9SRichard Henderson 45938eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 45948eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 459551b061fbSRichard Henderson { 4596c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 459761766fe9SRichard Henderson 4598ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4599ba1d0b44SRichard Henderson switch (pc) { 46007ad439dfSRichard Henderson case 0x00: 46018eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4602ba1d0b44SRichard Henderson return; 46037ad439dfSRichard Henderson case 0xb0: 46048eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4605ba1d0b44SRichard Henderson return; 46067ad439dfSRichard Henderson case 0xe0: 46078eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4608ba1d0b44SRichard Henderson return; 46097ad439dfSRichard Henderson case 0x100: 46108eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4611ba1d0b44SRichard Henderson return; 46127ad439dfSRichard Henderson } 4613ba1d0b44SRichard Henderson #endif 4614ba1d0b44SRichard Henderson 46158eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 46168eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 461761766fe9SRichard Henderson } 461851b061fbSRichard Henderson 461951b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 462051b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 462151b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 462251b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 462351b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 462451b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 462551b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 462651b061fbSRichard Henderson }; 462751b061fbSRichard Henderson 4628597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 4629306c8721SRichard Henderson target_ulong pc, void *host_pc) 463051b061fbSRichard Henderson { 463151b061fbSRichard Henderson DisasContext ctx; 4632306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 463361766fe9SRichard Henderson } 4634