161766fe9SRichard Henderson /* 261766fe9SRichard Henderson * HPPA emulation cpu translation for qemu. 361766fe9SRichard Henderson * 461766fe9SRichard Henderson * Copyright (c) 2016 Richard Henderson <rth@twiddle.net> 561766fe9SRichard Henderson * 661766fe9SRichard Henderson * This library is free software; you can redistribute it and/or 761766fe9SRichard Henderson * modify it under the terms of the GNU Lesser General Public 861766fe9SRichard Henderson * License as published by the Free Software Foundation; either 9d6ea4236SChetan Pant * version 2.1 of the License, or (at your option) any later version. 1061766fe9SRichard Henderson * 1161766fe9SRichard Henderson * This library is distributed in the hope that it will be useful, 1261766fe9SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 1361766fe9SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1461766fe9SRichard Henderson * Lesser General Public License for more details. 1561766fe9SRichard Henderson * 1661766fe9SRichard Henderson * You should have received a copy of the GNU Lesser General Public 1761766fe9SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1861766fe9SRichard Henderson */ 1961766fe9SRichard Henderson 2061766fe9SRichard Henderson #include "qemu/osdep.h" 2161766fe9SRichard Henderson #include "cpu.h" 2261766fe9SRichard Henderson #include "disas/disas.h" 2361766fe9SRichard Henderson #include "qemu/host-utils.h" 2461766fe9SRichard Henderson #include "exec/exec-all.h" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 260843563fSRichard Henderson #include "tcg/tcg-op-gvec.h" 2761766fe9SRichard Henderson #include "exec/helper-proto.h" 2861766fe9SRichard Henderson #include "exec/helper-gen.h" 29869051eaSRichard Henderson #include "exec/translator.h" 3061766fe9SRichard Henderson #include "exec/log.h" 3161766fe9SRichard Henderson 32d53106c9SRichard Henderson #define HELPER_H "helper.h" 33d53106c9SRichard Henderson #include "exec/helper-info.c.inc" 34d53106c9SRichard Henderson #undef HELPER_H 35d53106c9SRichard Henderson 36aac0f603SRichard Henderson /* Choose to use explicit sizes within this file. */ 37aac0f603SRichard Henderson #undef tcg_temp_new 38d53106c9SRichard Henderson 3961766fe9SRichard Henderson typedef struct DisasCond { 4061766fe9SRichard Henderson TCGCond c; 416fd0c7bcSRichard Henderson TCGv_i64 a0, a1; 4261766fe9SRichard Henderson } DisasCond; 4361766fe9SRichard Henderson 4461766fe9SRichard Henderson typedef struct DisasContext { 45d01a3625SRichard Henderson DisasContextBase base; 4661766fe9SRichard Henderson CPUState *cs; 47f5b5c857SRichard Henderson TCGOp *insn_start; 4861766fe9SRichard Henderson 49c53e401eSRichard Henderson uint64_t iaoq_f; 50c53e401eSRichard Henderson uint64_t iaoq_b; 51c53e401eSRichard Henderson uint64_t iaoq_n; 526fd0c7bcSRichard Henderson TCGv_i64 iaoq_n_var; 5361766fe9SRichard Henderson 5461766fe9SRichard Henderson DisasCond null_cond; 5561766fe9SRichard Henderson TCGLabel *null_lab; 5661766fe9SRichard Henderson 57a4db4a78SRichard Henderson TCGv_i64 zero; 58a4db4a78SRichard Henderson 591a19da0dSRichard Henderson uint32_t insn; 60494737b7SRichard Henderson uint32_t tb_flags; 613d68ee7bSRichard Henderson int mmu_idx; 623d68ee7bSRichard Henderson int privilege; 6361766fe9SRichard Henderson bool psw_n_nonzero; 64bd6243a3SRichard Henderson bool is_pa20; 65217d1a5eSRichard Henderson 66217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 67217d1a5eSRichard Henderson MemOp unalign; 68217d1a5eSRichard Henderson #endif 6961766fe9SRichard Henderson } DisasContext; 7061766fe9SRichard Henderson 71217d1a5eSRichard Henderson #ifdef CONFIG_USER_ONLY 72217d1a5eSRichard Henderson #define UNALIGN(C) (C)->unalign 7317fe594cSRichard Henderson #define MMU_DISABLED(C) false 74217d1a5eSRichard Henderson #else 752d4afb03SRichard Henderson #define UNALIGN(C) MO_ALIGN 7617fe594cSRichard Henderson #define MMU_DISABLED(C) MMU_IDX_MMU_DISABLED((C)->mmu_idx) 77217d1a5eSRichard Henderson #endif 78217d1a5eSRichard Henderson 79e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 80451e4ffdSRichard Henderson static int expand_sm_imm(DisasContext *ctx, int val) 81e36f27efSRichard Henderson { 82881d1073SHelge Deller /* Keep unimplemented bits disabled -- see cpu_hppa_put_psw. */ 83881d1073SHelge Deller if (ctx->is_pa20) { 84e36f27efSRichard Henderson if (val & PSW_SM_W) { 85881d1073SHelge Deller val |= PSW_W; 86881d1073SHelge Deller } 87881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_G); 88881d1073SHelge Deller } else { 89881d1073SHelge Deller val &= ~(PSW_SM_W | PSW_SM_E | PSW_O); 90e36f27efSRichard Henderson } 91e36f27efSRichard Henderson return val; 92e36f27efSRichard Henderson } 93e36f27efSRichard Henderson 94deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base. */ 95451e4ffdSRichard Henderson static int expand_sr3x(DisasContext *ctx, int val) 96deee69a1SRichard Henderson { 97deee69a1SRichard Henderson return ~val; 98deee69a1SRichard Henderson } 99deee69a1SRichard Henderson 1001cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value 1011cd012a5SRichard Henderson we use for the final M. */ 102451e4ffdSRichard Henderson static int ma_to_m(DisasContext *ctx, int val) 1031cd012a5SRichard Henderson { 1041cd012a5SRichard Henderson return val & 2 ? (val & 1 ? -1 : 1) : 0; 1051cd012a5SRichard Henderson } 1061cd012a5SRichard Henderson 107740038d7SRichard Henderson /* Convert the sign of the displacement to a pre or post-modify. */ 108451e4ffdSRichard Henderson static int pos_to_m(DisasContext *ctx, int val) 109740038d7SRichard Henderson { 110740038d7SRichard Henderson return val ? 1 : -1; 111740038d7SRichard Henderson } 112740038d7SRichard Henderson 113451e4ffdSRichard Henderson static int neg_to_m(DisasContext *ctx, int val) 114740038d7SRichard Henderson { 115740038d7SRichard Henderson return val ? -1 : 1; 116740038d7SRichard Henderson } 117740038d7SRichard Henderson 118740038d7SRichard Henderson /* Used for branch targets and fp memory ops. */ 119451e4ffdSRichard Henderson static int expand_shl2(DisasContext *ctx, int val) 12001afb7beSRichard Henderson { 12101afb7beSRichard Henderson return val << 2; 12201afb7beSRichard Henderson } 12301afb7beSRichard Henderson 1240588e061SRichard Henderson /* Used for assemble_21. */ 125451e4ffdSRichard Henderson static int expand_shl11(DisasContext *ctx, int val) 1260588e061SRichard Henderson { 1270588e061SRichard Henderson return val << 11; 1280588e061SRichard Henderson } 1290588e061SRichard Henderson 13072ae4f2bSRichard Henderson static int assemble_6(DisasContext *ctx, int val) 13172ae4f2bSRichard Henderson { 13272ae4f2bSRichard Henderson /* 13372ae4f2bSRichard Henderson * Officially, 32 * x + 32 - y. 13472ae4f2bSRichard Henderson * Here, x is already in bit 5, and y is [4:0]. 13572ae4f2bSRichard Henderson * Since -y = ~y + 1, in 5 bits 32 - y => y ^ 31 + 1, 13672ae4f2bSRichard Henderson * with the overflow from bit 4 summing with x. 13772ae4f2bSRichard Henderson */ 13872ae4f2bSRichard Henderson return (val ^ 31) + 1; 13972ae4f2bSRichard Henderson } 14072ae4f2bSRichard Henderson 141*4768c28eSRichard Henderson /* Expander for assemble_16a(s,cat(im10a,0),i). */ 142*4768c28eSRichard Henderson static int expand_11a(DisasContext *ctx, int val) 143*4768c28eSRichard Henderson { 144*4768c28eSRichard Henderson /* 145*4768c28eSRichard Henderson * @val is bit 0 and bits [4:15]. 146*4768c28eSRichard Henderson * Swizzle thing around depending on PSW.W. 147*4768c28eSRichard Henderson */ 148*4768c28eSRichard Henderson int im10a = extract32(val, 1, 10); 149*4768c28eSRichard Henderson int s = extract32(val, 11, 2); 150*4768c28eSRichard Henderson int i = (-(val & 1) << 13) | (im10a << 3); 151*4768c28eSRichard Henderson 152*4768c28eSRichard Henderson if (ctx->tb_flags & PSW_W) { 153*4768c28eSRichard Henderson i ^= s << 13; 154*4768c28eSRichard Henderson } 155*4768c28eSRichard Henderson return i; 156*4768c28eSRichard Henderson } 157*4768c28eSRichard Henderson 15872bace2dSRichard Henderson /* Expander for assemble_16(s,im14). */ 15972bace2dSRichard Henderson static int expand_16(DisasContext *ctx, int val) 16072bace2dSRichard Henderson { 16172bace2dSRichard Henderson /* 16272bace2dSRichard Henderson * @val is bits [0:15], containing both im14 and s. 16372bace2dSRichard Henderson * Swizzle thing around depending on PSW.W. 16472bace2dSRichard Henderson */ 16572bace2dSRichard Henderson int s = extract32(val, 14, 2); 16672bace2dSRichard Henderson int i = (-(val & 1) << 13) | extract32(val, 1, 13); 16772bace2dSRichard Henderson 16872bace2dSRichard Henderson if (ctx->tb_flags & PSW_W) { 16972bace2dSRichard Henderson i ^= s << 13; 17072bace2dSRichard Henderson } 17172bace2dSRichard Henderson return i; 17272bace2dSRichard Henderson } 17372bace2dSRichard Henderson 17472bace2dSRichard Henderson /* The sp field is only present with !PSW_W. */ 17572bace2dSRichard Henderson static int sp0_if_wide(DisasContext *ctx, int sp) 17672bace2dSRichard Henderson { 17772bace2dSRichard Henderson return ctx->tb_flags & PSW_W ? 0 : sp; 17872bace2dSRichard Henderson } 17972bace2dSRichard Henderson 180c65c3ee1SRichard Henderson /* Translate CMPI doubleword conditions to standard. */ 181c65c3ee1SRichard Henderson static int cmpbid_c(DisasContext *ctx, int val) 182c65c3ee1SRichard Henderson { 183c65c3ee1SRichard Henderson return val ? val : 4; /* 0 == "*<<" */ 184c65c3ee1SRichard Henderson } 185c65c3ee1SRichard Henderson 18601afb7beSRichard Henderson 18740f9f908SRichard Henderson /* Include the auto-generated decoder. */ 188abff1abfSPaolo Bonzini #include "decode-insns.c.inc" 18940f9f908SRichard Henderson 19061766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 19161766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 192869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 19361766fe9SRichard Henderson 19461766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 19561766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 196869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 19761766fe9SRichard Henderson 198e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 199e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 200e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 201c5d0aec2SRichard Henderson #define DISAS_EXIT DISAS_TARGET_3 202e1b5a5edSRichard Henderson 20361766fe9SRichard Henderson /* global register indexes */ 2046fd0c7bcSRichard Henderson static TCGv_i64 cpu_gr[32]; 20533423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 206494737b7SRichard Henderson static TCGv_i64 cpu_srH; 2076fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_f; 2086fd0c7bcSRichard Henderson static TCGv_i64 cpu_iaoq_b; 209c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 210c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 2116fd0c7bcSRichard Henderson static TCGv_i64 cpu_sar; 2126fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_n; 2136fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_v; 2146fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb; 2156fd0c7bcSRichard Henderson static TCGv_i64 cpu_psw_cb_msb; 21661766fe9SRichard Henderson 21761766fe9SRichard Henderson void hppa_translate_init(void) 21861766fe9SRichard Henderson { 21961766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 22061766fe9SRichard Henderson 2216fd0c7bcSRichard Henderson typedef struct { TCGv_i64 *var; const char *name; int ofs; } GlobalVar; 22261766fe9SRichard Henderson static const GlobalVar vars[] = { 22335136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 22461766fe9SRichard Henderson DEF_VAR(psw_n), 22561766fe9SRichard Henderson DEF_VAR(psw_v), 22661766fe9SRichard Henderson DEF_VAR(psw_cb), 22761766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 22861766fe9SRichard Henderson DEF_VAR(iaoq_f), 22961766fe9SRichard Henderson DEF_VAR(iaoq_b), 23061766fe9SRichard Henderson }; 23161766fe9SRichard Henderson 23261766fe9SRichard Henderson #undef DEF_VAR 23361766fe9SRichard Henderson 23461766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 23561766fe9SRichard Henderson static const char gr_names[32][4] = { 23661766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 23761766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 23861766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 23961766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 24061766fe9SRichard Henderson }; 24133423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 242494737b7SRichard Henderson static const char sr_names[5][4] = { 243494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 24433423472SRichard Henderson }; 24561766fe9SRichard Henderson 24661766fe9SRichard Henderson int i; 24761766fe9SRichard Henderson 248f764718dSRichard Henderson cpu_gr[0] = NULL; 24961766fe9SRichard Henderson for (i = 1; i < 32; i++) { 250ad75a51eSRichard Henderson cpu_gr[i] = tcg_global_mem_new(tcg_env, 25161766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 25261766fe9SRichard Henderson gr_names[i]); 25361766fe9SRichard Henderson } 25433423472SRichard Henderson for (i = 0; i < 4; i++) { 255ad75a51eSRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(tcg_env, 25633423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 25733423472SRichard Henderson sr_names[i]); 25833423472SRichard Henderson } 259ad75a51eSRichard Henderson cpu_srH = tcg_global_mem_new_i64(tcg_env, 260494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 261494737b7SRichard Henderson sr_names[4]); 26261766fe9SRichard Henderson 26361766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 26461766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 265ad75a51eSRichard Henderson *v->var = tcg_global_mem_new(tcg_env, v->ofs, v->name); 26661766fe9SRichard Henderson } 267c301f34eSRichard Henderson 268ad75a51eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(tcg_env, 269c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 270c301f34eSRichard Henderson "iasq_f"); 271ad75a51eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(tcg_env, 272c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 273c301f34eSRichard Henderson "iasq_b"); 27461766fe9SRichard Henderson } 27561766fe9SRichard Henderson 276f5b5c857SRichard Henderson static void set_insn_breg(DisasContext *ctx, int breg) 277f5b5c857SRichard Henderson { 278f5b5c857SRichard Henderson assert(ctx->insn_start != NULL); 279f5b5c857SRichard Henderson tcg_set_insn_start_param(ctx->insn_start, 2, breg); 280f5b5c857SRichard Henderson ctx->insn_start = NULL; 281f5b5c857SRichard Henderson } 282f5b5c857SRichard Henderson 283129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 284129e9cc3SRichard Henderson { 285f764718dSRichard Henderson return (DisasCond){ 286f764718dSRichard Henderson .c = TCG_COND_NEVER, 287f764718dSRichard Henderson .a0 = NULL, 288f764718dSRichard Henderson .a1 = NULL, 289f764718dSRichard Henderson }; 290129e9cc3SRichard Henderson } 291129e9cc3SRichard Henderson 292df0232feSRichard Henderson static DisasCond cond_make_t(void) 293df0232feSRichard Henderson { 294df0232feSRichard Henderson return (DisasCond){ 295df0232feSRichard Henderson .c = TCG_COND_ALWAYS, 296df0232feSRichard Henderson .a0 = NULL, 297df0232feSRichard Henderson .a1 = NULL, 298df0232feSRichard Henderson }; 299df0232feSRichard Henderson } 300df0232feSRichard Henderson 301129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 302129e9cc3SRichard Henderson { 303f764718dSRichard Henderson return (DisasCond){ 304f764718dSRichard Henderson .c = TCG_COND_NE, 305f764718dSRichard Henderson .a0 = cpu_psw_n, 3066fd0c7bcSRichard Henderson .a1 = tcg_constant_i64(0) 307f764718dSRichard Henderson }; 308129e9cc3SRichard Henderson } 309129e9cc3SRichard Henderson 3106fd0c7bcSRichard Henderson static DisasCond cond_make_tmp(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 311b47a4a02SSven Schnelle { 312b47a4a02SSven Schnelle assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 3134fe9533aSRichard Henderson return (DisasCond){ .c = c, .a0 = a0, .a1 = a1 }; 3144fe9533aSRichard Henderson } 3154fe9533aSRichard Henderson 3166fd0c7bcSRichard Henderson static DisasCond cond_make_0_tmp(TCGCond c, TCGv_i64 a0) 3174fe9533aSRichard Henderson { 3186fd0c7bcSRichard Henderson return cond_make_tmp(c, a0, tcg_constant_i64(0)); 319b47a4a02SSven Schnelle } 320b47a4a02SSven Schnelle 3216fd0c7bcSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_i64 a0) 322129e9cc3SRichard Henderson { 323aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3246fd0c7bcSRichard Henderson tcg_gen_mov_i64(tmp, a0); 325b47a4a02SSven Schnelle return cond_make_0_tmp(c, tmp); 326129e9cc3SRichard Henderson } 327129e9cc3SRichard Henderson 3286fd0c7bcSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_i64 a0, TCGv_i64 a1) 329129e9cc3SRichard Henderson { 330aac0f603SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 331aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 332129e9cc3SRichard Henderson 3336fd0c7bcSRichard Henderson tcg_gen_mov_i64(t0, a0); 3346fd0c7bcSRichard Henderson tcg_gen_mov_i64(t1, a1); 3354fe9533aSRichard Henderson return cond_make_tmp(c, t0, t1); 336129e9cc3SRichard Henderson } 337129e9cc3SRichard Henderson 338129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 339129e9cc3SRichard Henderson { 340129e9cc3SRichard Henderson switch (cond->c) { 341129e9cc3SRichard Henderson default: 342f764718dSRichard Henderson cond->a0 = NULL; 343f764718dSRichard Henderson cond->a1 = NULL; 344129e9cc3SRichard Henderson /* fallthru */ 345129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 346129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 347129e9cc3SRichard Henderson break; 348129e9cc3SRichard Henderson case TCG_COND_NEVER: 349129e9cc3SRichard Henderson break; 350129e9cc3SRichard Henderson } 351129e9cc3SRichard Henderson } 352129e9cc3SRichard Henderson 3536fd0c7bcSRichard Henderson static TCGv_i64 load_gpr(DisasContext *ctx, unsigned reg) 35461766fe9SRichard Henderson { 35561766fe9SRichard Henderson if (reg == 0) { 356bc3da3cfSRichard Henderson return ctx->zero; 35761766fe9SRichard Henderson } else { 35861766fe9SRichard Henderson return cpu_gr[reg]; 35961766fe9SRichard Henderson } 36061766fe9SRichard Henderson } 36161766fe9SRichard Henderson 3626fd0c7bcSRichard Henderson static TCGv_i64 dest_gpr(DisasContext *ctx, unsigned reg) 36361766fe9SRichard Henderson { 364129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 365aac0f603SRichard Henderson return tcg_temp_new_i64(); 36661766fe9SRichard Henderson } else { 36761766fe9SRichard Henderson return cpu_gr[reg]; 36861766fe9SRichard Henderson } 36961766fe9SRichard Henderson } 37061766fe9SRichard Henderson 3716fd0c7bcSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_i64 dest, TCGv_i64 t) 372129e9cc3SRichard Henderson { 373129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 3746fd0c7bcSRichard Henderson tcg_gen_movcond_i64(ctx->null_cond.c, dest, ctx->null_cond.a0, 375129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 376129e9cc3SRichard Henderson } else { 3776fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, t); 378129e9cc3SRichard Henderson } 379129e9cc3SRichard Henderson } 380129e9cc3SRichard Henderson 3816fd0c7bcSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_i64 t) 382129e9cc3SRichard Henderson { 383129e9cc3SRichard Henderson if (reg != 0) { 384129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 385129e9cc3SRichard Henderson } 386129e9cc3SRichard Henderson } 387129e9cc3SRichard Henderson 388e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 38996d6407fSRichard Henderson # define HI_OFS 0 39096d6407fSRichard Henderson # define LO_OFS 4 39196d6407fSRichard Henderson #else 39296d6407fSRichard Henderson # define HI_OFS 4 39396d6407fSRichard Henderson # define LO_OFS 0 39496d6407fSRichard Henderson #endif 39596d6407fSRichard Henderson 39696d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 39796d6407fSRichard Henderson { 39896d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 399ad75a51eSRichard Henderson tcg_gen_ld_i32(ret, tcg_env, 40096d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 40196d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 40296d6407fSRichard Henderson return ret; 40396d6407fSRichard Henderson } 40496d6407fSRichard Henderson 405ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 406ebe9383cSRichard Henderson { 407ebe9383cSRichard Henderson if (rt == 0) { 4080992a930SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 4090992a930SRichard Henderson tcg_gen_movi_i32(ret, 0); 4100992a930SRichard Henderson return ret; 411ebe9383cSRichard Henderson } else { 412ebe9383cSRichard Henderson return load_frw_i32(rt); 413ebe9383cSRichard Henderson } 414ebe9383cSRichard Henderson } 415ebe9383cSRichard Henderson 416ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 417ebe9383cSRichard Henderson { 418ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4190992a930SRichard Henderson if (rt == 0) { 4200992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4210992a930SRichard Henderson } else { 422ad75a51eSRichard Henderson tcg_gen_ld32u_i64(ret, tcg_env, 423ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 424ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 425ebe9383cSRichard Henderson } 4260992a930SRichard Henderson return ret; 427ebe9383cSRichard Henderson } 428ebe9383cSRichard Henderson 42996d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 43096d6407fSRichard Henderson { 431ad75a51eSRichard Henderson tcg_gen_st_i32(val, tcg_env, 43296d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 43396d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 43496d6407fSRichard Henderson } 43596d6407fSRichard Henderson 43696d6407fSRichard Henderson #undef HI_OFS 43796d6407fSRichard Henderson #undef LO_OFS 43896d6407fSRichard Henderson 43996d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 44096d6407fSRichard Henderson { 44196d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 442ad75a51eSRichard Henderson tcg_gen_ld_i64(ret, tcg_env, offsetof(CPUHPPAState, fr[rt])); 44396d6407fSRichard Henderson return ret; 44496d6407fSRichard Henderson } 44596d6407fSRichard Henderson 446ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 447ebe9383cSRichard Henderson { 448ebe9383cSRichard Henderson if (rt == 0) { 4490992a930SRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 4500992a930SRichard Henderson tcg_gen_movi_i64(ret, 0); 4510992a930SRichard Henderson return ret; 452ebe9383cSRichard Henderson } else { 453ebe9383cSRichard Henderson return load_frd(rt); 454ebe9383cSRichard Henderson } 455ebe9383cSRichard Henderson } 456ebe9383cSRichard Henderson 45796d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 45896d6407fSRichard Henderson { 459ad75a51eSRichard Henderson tcg_gen_st_i64(val, tcg_env, offsetof(CPUHPPAState, fr[rt])); 46096d6407fSRichard Henderson } 46196d6407fSRichard Henderson 46233423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 46333423472SRichard Henderson { 46433423472SRichard Henderson #ifdef CONFIG_USER_ONLY 46533423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 46633423472SRichard Henderson #else 46733423472SRichard Henderson if (reg < 4) { 46833423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 469494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 470494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 47133423472SRichard Henderson } else { 472ad75a51eSRichard Henderson tcg_gen_ld_i64(dest, tcg_env, offsetof(CPUHPPAState, sr[reg])); 47333423472SRichard Henderson } 47433423472SRichard Henderson #endif 47533423472SRichard Henderson } 47633423472SRichard Henderson 477129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 478129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 479129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 480129e9cc3SRichard Henderson { 481129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 482129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 483129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 484129e9cc3SRichard Henderson 485129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 486129e9cc3SRichard Henderson 487129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 4886e94937aSRichard Henderson if (ctx->null_cond.a0 == cpu_psw_n) { 489aac0f603SRichard Henderson ctx->null_cond.a0 = tcg_temp_new_i64(); 4906fd0c7bcSRichard Henderson tcg_gen_mov_i64(ctx->null_cond.a0, cpu_psw_n); 491129e9cc3SRichard Henderson } 492129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 493129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 494129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 495129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 496129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 4976fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 498129e9cc3SRichard Henderson } 499129e9cc3SRichard Henderson 5006fd0c7bcSRichard Henderson tcg_gen_brcond_i64(ctx->null_cond.c, ctx->null_cond.a0, 501129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 502129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 503129e9cc3SRichard Henderson } 504129e9cc3SRichard Henderson } 505129e9cc3SRichard Henderson 506129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 507129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 508129e9cc3SRichard Henderson { 509129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 510129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 5116fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 512129e9cc3SRichard Henderson } 513129e9cc3SRichard Henderson return; 514129e9cc3SRichard Henderson } 5156e94937aSRichard Henderson if (ctx->null_cond.a0 != cpu_psw_n) { 5166fd0c7bcSRichard Henderson tcg_gen_setcond_i64(ctx->null_cond.c, cpu_psw_n, 517129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 518129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 519129e9cc3SRichard Henderson } 520129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 521129e9cc3SRichard Henderson } 522129e9cc3SRichard Henderson 523129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 524129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 525129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 526129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 527129e9cc3SRichard Henderson { 528129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 5296fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, x); 530129e9cc3SRichard Henderson } 531129e9cc3SRichard Henderson } 532129e9cc3SRichard Henderson 533129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 53440f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 53540f9f908SRichard Henderson it may be tail-called from a translate function. */ 53631234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 537129e9cc3SRichard Henderson { 538129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 53931234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 540129e9cc3SRichard Henderson 541f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 542f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 543f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 544f49b3537SRichard Henderson 545129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 546129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 547129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 548129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 54931234768SRichard Henderson return true; 550129e9cc3SRichard Henderson } 551129e9cc3SRichard Henderson ctx->null_lab = NULL; 552129e9cc3SRichard Henderson 553129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 554129e9cc3SRichard Henderson /* The next instruction will be unconditional, 555129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 556129e9cc3SRichard Henderson gen_set_label(null_lab); 557129e9cc3SRichard Henderson } else { 558129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 559129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 560129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 561129e9cc3SRichard Henderson label we have the proper value in place. */ 562129e9cc3SRichard Henderson nullify_save(ctx); 563129e9cc3SRichard Henderson gen_set_label(null_lab); 564129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 565129e9cc3SRichard Henderson } 566869051eaSRichard Henderson if (status == DISAS_NORETURN) { 56731234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 568129e9cc3SRichard Henderson } 56931234768SRichard Henderson return true; 570129e9cc3SRichard Henderson } 571129e9cc3SRichard Henderson 572c53e401eSRichard Henderson static uint64_t gva_offset_mask(DisasContext *ctx) 573698240d1SRichard Henderson { 574698240d1SRichard Henderson return (ctx->tb_flags & PSW_W 575698240d1SRichard Henderson ? MAKE_64BIT_MASK(0, 62) 576698240d1SRichard Henderson : MAKE_64BIT_MASK(0, 32)); 577698240d1SRichard Henderson } 578698240d1SRichard Henderson 5796fd0c7bcSRichard Henderson static void copy_iaoq_entry(DisasContext *ctx, TCGv_i64 dest, 5806fd0c7bcSRichard Henderson uint64_t ival, TCGv_i64 vval) 58161766fe9SRichard Henderson { 582c53e401eSRichard Henderson uint64_t mask = gva_offset_mask(ctx); 583f13bf343SRichard Henderson 584f13bf343SRichard Henderson if (ival != -1) { 5856fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, ival & mask); 586f13bf343SRichard Henderson return; 587f13bf343SRichard Henderson } 588f13bf343SRichard Henderson tcg_debug_assert(vval != NULL); 589f13bf343SRichard Henderson 590f13bf343SRichard Henderson /* 591f13bf343SRichard Henderson * We know that the IAOQ is already properly masked. 592f13bf343SRichard Henderson * This optimization is primarily for "iaoq_f = iaoq_b". 593f13bf343SRichard Henderson */ 594f13bf343SRichard Henderson if (vval == cpu_iaoq_f || vval == cpu_iaoq_b) { 5956fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, vval); 59661766fe9SRichard Henderson } else { 5976fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, vval, mask); 59861766fe9SRichard Henderson } 59961766fe9SRichard Henderson } 60061766fe9SRichard Henderson 601c53e401eSRichard Henderson static inline uint64_t iaoq_dest(DisasContext *ctx, int64_t disp) 60261766fe9SRichard Henderson { 60361766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 60461766fe9SRichard Henderson } 60561766fe9SRichard Henderson 60661766fe9SRichard Henderson static void gen_excp_1(int exception) 60761766fe9SRichard Henderson { 608ad75a51eSRichard Henderson gen_helper_excp(tcg_env, tcg_constant_i32(exception)); 60961766fe9SRichard Henderson } 61061766fe9SRichard Henderson 61131234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 61261766fe9SRichard Henderson { 613741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 614741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 615129e9cc3SRichard Henderson nullify_save(ctx); 61661766fe9SRichard Henderson gen_excp_1(exception); 61731234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 61861766fe9SRichard Henderson } 61961766fe9SRichard Henderson 62031234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 6211a19da0dSRichard Henderson { 62231234768SRichard Henderson nullify_over(ctx); 6236fd0c7bcSRichard Henderson tcg_gen_st_i64(tcg_constant_i64(ctx->insn), 624ad75a51eSRichard Henderson tcg_env, offsetof(CPUHPPAState, cr[CR_IIR])); 62531234768SRichard Henderson gen_excp(ctx, exc); 62631234768SRichard Henderson return nullify_end(ctx); 6271a19da0dSRichard Henderson } 6281a19da0dSRichard Henderson 62931234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 63061766fe9SRichard Henderson { 63131234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 63261766fe9SRichard Henderson } 63361766fe9SRichard Henderson 63440f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 63540f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 63640f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 63740f9f908SRichard Henderson #else 638e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 639e1b5a5edSRichard Henderson do { \ 640e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 64131234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 642e1b5a5edSRichard Henderson } \ 643e1b5a5edSRichard Henderson } while (0) 64440f9f908SRichard Henderson #endif 645e1b5a5edSRichard Henderson 646c53e401eSRichard Henderson static bool use_goto_tb(DisasContext *ctx, uint64_t dest) 64761766fe9SRichard Henderson { 64857f91498SRichard Henderson return translator_use_goto_tb(&ctx->base, dest); 64961766fe9SRichard Henderson } 65061766fe9SRichard Henderson 651129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 652129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 653129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 654129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 655129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 656129e9cc3SRichard Henderson { 657129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 658129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 659129e9cc3SRichard Henderson } 660129e9cc3SRichard Henderson 66161766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 662c53e401eSRichard Henderson uint64_t f, uint64_t b) 66361766fe9SRichard Henderson { 66461766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 66561766fe9SRichard Henderson tcg_gen_goto_tb(which); 666a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, NULL); 667a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, NULL); 66807ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 66961766fe9SRichard Henderson } else { 670741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, f, cpu_iaoq_b); 671741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, b, ctx->iaoq_n_var); 6727f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 67361766fe9SRichard Henderson } 67461766fe9SRichard Henderson } 67561766fe9SRichard Henderson 676b47a4a02SSven Schnelle static bool cond_need_sv(int c) 677b47a4a02SSven Schnelle { 678b47a4a02SSven Schnelle return c == 2 || c == 3 || c == 6; 679b47a4a02SSven Schnelle } 680b47a4a02SSven Schnelle 681b47a4a02SSven Schnelle static bool cond_need_cb(int c) 682b47a4a02SSven Schnelle { 683b47a4a02SSven Schnelle return c == 4 || c == 5; 684b47a4a02SSven Schnelle } 685b47a4a02SSven Schnelle 6866fd0c7bcSRichard Henderson /* Need extensions from TCGv_i32 to TCGv_i64. */ 68772ca8753SRichard Henderson static bool cond_need_ext(DisasContext *ctx, bool d) 68872ca8753SRichard Henderson { 689c53e401eSRichard Henderson return !(ctx->is_pa20 && d); 69072ca8753SRichard Henderson } 69172ca8753SRichard Henderson 692b47a4a02SSven Schnelle /* 693b47a4a02SSven Schnelle * Compute conditional for arithmetic. See Page 5-3, Table 5-1, of 694b47a4a02SSven Schnelle * the Parisc 1.1 Architecture Reference Manual for details. 695b47a4a02SSven Schnelle */ 696b2167459SRichard Henderson 697a751eb31SRichard Henderson static DisasCond do_cond(DisasContext *ctx, unsigned cf, bool d, 6986fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 cb_msb, TCGv_i64 sv) 699b2167459SRichard Henderson { 700b2167459SRichard Henderson DisasCond cond; 7016fd0c7bcSRichard Henderson TCGv_i64 tmp; 702b2167459SRichard Henderson 703b2167459SRichard Henderson switch (cf >> 1) { 704b47a4a02SSven Schnelle case 0: /* Never / TR (0 / 1) */ 705b2167459SRichard Henderson cond = cond_make_f(); 706b2167459SRichard Henderson break; 707b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 708a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 709aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7106fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 711a751eb31SRichard Henderson res = tmp; 712a751eb31SRichard Henderson } 713b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 714b2167459SRichard Henderson break; 715b47a4a02SSven Schnelle case 2: /* < / >= (N ^ V / !(N ^ V) */ 716aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7176fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, res, sv); 718a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7196fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, tmp); 720a751eb31SRichard Henderson } 721b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_LT, tmp); 722b2167459SRichard Henderson break; 723b47a4a02SSven Schnelle case 3: /* <= / > (N ^ V) | Z / !((N ^ V) | Z) */ 724b47a4a02SSven Schnelle /* 725b47a4a02SSven Schnelle * Simplify: 726b47a4a02SSven Schnelle * (N ^ V) | Z 727b47a4a02SSven Schnelle * ((res < 0) ^ (sv < 0)) | !res 728b47a4a02SSven Schnelle * ((res ^ sv) < 0) | !res 729b47a4a02SSven Schnelle * (~(res ^ sv) >= 0) | !res 730b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31) | !res 731b47a4a02SSven Schnelle * !(~(res ^ sv) >> 31 & res) 732b47a4a02SSven Schnelle */ 733aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7346fd0c7bcSRichard Henderson tcg_gen_eqv_i64(tmp, res, sv); 735a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7366fd0c7bcSRichard Henderson tcg_gen_sextract_i64(tmp, tmp, 31, 1); 7376fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 7386fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 739a751eb31SRichard Henderson } else { 7406fd0c7bcSRichard Henderson tcg_gen_sari_i64(tmp, tmp, 63); 7416fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 742a751eb31SRichard Henderson } 743b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 744b2167459SRichard Henderson break; 745b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 746a751eb31SRichard Henderson /* Only bit 0 of cb_msb is ever set. */ 747b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 748b2167459SRichard Henderson break; 749b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 750aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7516fd0c7bcSRichard Henderson tcg_gen_neg_i64(tmp, cb_msb); 7526fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, tmp, res); 753a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 7546fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, tmp); 755a751eb31SRichard Henderson } 756b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_EQ, tmp); 757b2167459SRichard Henderson break; 758b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 759a751eb31SRichard Henderson if (cond_need_ext(ctx, d)) { 760aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7616fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, sv); 762a751eb31SRichard Henderson sv = tmp; 763a751eb31SRichard Henderson } 764b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 765b2167459SRichard Henderson break; 766b2167459SRichard Henderson case 7: /* OD / EV */ 767aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 7686fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, res, 1); 769b47a4a02SSven Schnelle cond = cond_make_0_tmp(TCG_COND_NE, tmp); 770b2167459SRichard Henderson break; 771b2167459SRichard Henderson default: 772b2167459SRichard Henderson g_assert_not_reached(); 773b2167459SRichard Henderson } 774b2167459SRichard Henderson if (cf & 1) { 775b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 776b2167459SRichard Henderson } 777b2167459SRichard Henderson 778b2167459SRichard Henderson return cond; 779b2167459SRichard Henderson } 780b2167459SRichard Henderson 781b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 782b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 783b2167459SRichard Henderson deleted as unused. */ 784b2167459SRichard Henderson 7854fe9533aSRichard Henderson static DisasCond do_sub_cond(DisasContext *ctx, unsigned cf, bool d, 7866fd0c7bcSRichard Henderson TCGv_i64 res, TCGv_i64 in1, 7876fd0c7bcSRichard Henderson TCGv_i64 in2, TCGv_i64 sv) 788b2167459SRichard Henderson { 7894fe9533aSRichard Henderson TCGCond tc; 7904fe9533aSRichard Henderson bool ext_uns; 791b2167459SRichard Henderson 792b2167459SRichard Henderson switch (cf >> 1) { 793b2167459SRichard Henderson case 1: /* = / <> */ 7944fe9533aSRichard Henderson tc = TCG_COND_EQ; 7954fe9533aSRichard Henderson ext_uns = true; 796b2167459SRichard Henderson break; 797b2167459SRichard Henderson case 2: /* < / >= */ 7984fe9533aSRichard Henderson tc = TCG_COND_LT; 7994fe9533aSRichard Henderson ext_uns = false; 800b2167459SRichard Henderson break; 801b2167459SRichard Henderson case 3: /* <= / > */ 8024fe9533aSRichard Henderson tc = TCG_COND_LE; 8034fe9533aSRichard Henderson ext_uns = false; 804b2167459SRichard Henderson break; 805b2167459SRichard Henderson case 4: /* << / >>= */ 8064fe9533aSRichard Henderson tc = TCG_COND_LTU; 8074fe9533aSRichard Henderson ext_uns = true; 808b2167459SRichard Henderson break; 809b2167459SRichard Henderson case 5: /* <<= / >> */ 8104fe9533aSRichard Henderson tc = TCG_COND_LEU; 8114fe9533aSRichard Henderson ext_uns = true; 812b2167459SRichard Henderson break; 813b2167459SRichard Henderson default: 814a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, sv); 815b2167459SRichard Henderson } 816b2167459SRichard Henderson 8174fe9533aSRichard Henderson if (cf & 1) { 8184fe9533aSRichard Henderson tc = tcg_invert_cond(tc); 8194fe9533aSRichard Henderson } 8204fe9533aSRichard Henderson if (cond_need_ext(ctx, d)) { 821aac0f603SRichard Henderson TCGv_i64 t1 = tcg_temp_new_i64(); 822aac0f603SRichard Henderson TCGv_i64 t2 = tcg_temp_new_i64(); 8234fe9533aSRichard Henderson 8244fe9533aSRichard Henderson if (ext_uns) { 8256fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t1, in1); 8266fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(t2, in2); 8274fe9533aSRichard Henderson } else { 8286fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t1, in1); 8296fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(t2, in2); 8304fe9533aSRichard Henderson } 8314fe9533aSRichard Henderson return cond_make_tmp(tc, t1, t2); 8324fe9533aSRichard Henderson } 8334fe9533aSRichard Henderson return cond_make(tc, in1, in2); 834b2167459SRichard Henderson } 835b2167459SRichard Henderson 836df0232feSRichard Henderson /* 837df0232feSRichard Henderson * Similar, but for logicals, where the carry and overflow bits are not 838df0232feSRichard Henderson * computed, and use of them is undefined. 839df0232feSRichard Henderson * 840df0232feSRichard Henderson * Undefined or not, hardware does not trap. It seems reasonable to 841df0232feSRichard Henderson * assume hardware treats cases c={4,5,6} as if C=0 & V=0, since that's 842df0232feSRichard Henderson * how cases c={2,3} are treated. 843df0232feSRichard Henderson */ 844b2167459SRichard Henderson 845b5af8423SRichard Henderson static DisasCond do_log_cond(DisasContext *ctx, unsigned cf, bool d, 8466fd0c7bcSRichard Henderson TCGv_i64 res) 847b2167459SRichard Henderson { 848b5af8423SRichard Henderson TCGCond tc; 849b5af8423SRichard Henderson bool ext_uns; 850a751eb31SRichard Henderson 851df0232feSRichard Henderson switch (cf) { 852df0232feSRichard Henderson case 0: /* never */ 853df0232feSRichard Henderson case 9: /* undef, C */ 854df0232feSRichard Henderson case 11: /* undef, C & !Z */ 855df0232feSRichard Henderson case 12: /* undef, V */ 856df0232feSRichard Henderson return cond_make_f(); 857df0232feSRichard Henderson 858df0232feSRichard Henderson case 1: /* true */ 859df0232feSRichard Henderson case 8: /* undef, !C */ 860df0232feSRichard Henderson case 10: /* undef, !C | Z */ 861df0232feSRichard Henderson case 13: /* undef, !V */ 862df0232feSRichard Henderson return cond_make_t(); 863df0232feSRichard Henderson 864df0232feSRichard Henderson case 2: /* == */ 865b5af8423SRichard Henderson tc = TCG_COND_EQ; 866b5af8423SRichard Henderson ext_uns = true; 867b5af8423SRichard Henderson break; 868df0232feSRichard Henderson case 3: /* <> */ 869b5af8423SRichard Henderson tc = TCG_COND_NE; 870b5af8423SRichard Henderson ext_uns = true; 871b5af8423SRichard Henderson break; 872df0232feSRichard Henderson case 4: /* < */ 873b5af8423SRichard Henderson tc = TCG_COND_LT; 874b5af8423SRichard Henderson ext_uns = false; 875b5af8423SRichard Henderson break; 876df0232feSRichard Henderson case 5: /* >= */ 877b5af8423SRichard Henderson tc = TCG_COND_GE; 878b5af8423SRichard Henderson ext_uns = false; 879b5af8423SRichard Henderson break; 880df0232feSRichard Henderson case 6: /* <= */ 881b5af8423SRichard Henderson tc = TCG_COND_LE; 882b5af8423SRichard Henderson ext_uns = false; 883b5af8423SRichard Henderson break; 884df0232feSRichard Henderson case 7: /* > */ 885b5af8423SRichard Henderson tc = TCG_COND_GT; 886b5af8423SRichard Henderson ext_uns = false; 887b5af8423SRichard Henderson break; 888df0232feSRichard Henderson 889df0232feSRichard Henderson case 14: /* OD */ 890df0232feSRichard Henderson case 15: /* EV */ 891a751eb31SRichard Henderson return do_cond(ctx, cf, d, res, NULL, NULL); 892df0232feSRichard Henderson 893df0232feSRichard Henderson default: 894df0232feSRichard Henderson g_assert_not_reached(); 895b2167459SRichard Henderson } 896b5af8423SRichard Henderson 897b5af8423SRichard Henderson if (cond_need_ext(ctx, d)) { 898aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 899b5af8423SRichard Henderson 900b5af8423SRichard Henderson if (ext_uns) { 9016fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(tmp, res); 902b5af8423SRichard Henderson } else { 9036fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(tmp, res); 904b5af8423SRichard Henderson } 905b5af8423SRichard Henderson return cond_make_0_tmp(tc, tmp); 906b5af8423SRichard Henderson } 907b5af8423SRichard Henderson return cond_make_0(tc, res); 908b2167459SRichard Henderson } 909b2167459SRichard Henderson 91098cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 91198cd9ca7SRichard Henderson 9124fa52edfSRichard Henderson static DisasCond do_sed_cond(DisasContext *ctx, unsigned orig, bool d, 9136fd0c7bcSRichard Henderson TCGv_i64 res) 91498cd9ca7SRichard Henderson { 91598cd9ca7SRichard Henderson unsigned c, f; 91698cd9ca7SRichard Henderson 91798cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 91898cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 91998cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 92098cd9ca7SRichard Henderson c = orig & 3; 92198cd9ca7SRichard Henderson if (c == 3) { 92298cd9ca7SRichard Henderson c = 7; 92398cd9ca7SRichard Henderson } 92498cd9ca7SRichard Henderson f = (orig & 4) / 4; 92598cd9ca7SRichard Henderson 926b5af8423SRichard Henderson return do_log_cond(ctx, c * 2 + f, d, res); 92798cd9ca7SRichard Henderson } 92898cd9ca7SRichard Henderson 929b2167459SRichard Henderson /* Similar, but for unit conditions. */ 930b2167459SRichard Henderson 9316fd0c7bcSRichard Henderson static DisasCond do_unit_cond(unsigned cf, bool d, TCGv_i64 res, 9326fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 933b2167459SRichard Henderson { 934b2167459SRichard Henderson DisasCond cond; 9356fd0c7bcSRichard Henderson TCGv_i64 tmp, cb = NULL; 936c53e401eSRichard Henderson uint64_t d_repl = d ? 0x0000000100000001ull : 1; 937b2167459SRichard Henderson 938b2167459SRichard Henderson if (cf & 8) { 939b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 940b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 941b2167459SRichard Henderson * leaves us with carry bits spread across two words. 942b2167459SRichard Henderson */ 943aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 944aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9456fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, in1, in2); 9466fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, in1, in2); 9476fd0c7bcSRichard Henderson tcg_gen_andc_i64(cb, cb, res); 9486fd0c7bcSRichard Henderson tcg_gen_or_i64(cb, cb, tmp); 949b2167459SRichard Henderson } 950b2167459SRichard Henderson 951b2167459SRichard Henderson switch (cf >> 1) { 952b2167459SRichard Henderson case 0: /* never / TR */ 953b2167459SRichard Henderson case 1: /* undefined */ 954b2167459SRichard Henderson case 5: /* undefined */ 955b2167459SRichard Henderson cond = cond_make_f(); 956b2167459SRichard Henderson break; 957b2167459SRichard Henderson 958b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 959b2167459SRichard Henderson /* See hasless(v,1) from 960b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 961b2167459SRichard Henderson */ 962aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9636fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x01010101u); 9646fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9656fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80808080u); 966b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 967b2167459SRichard Henderson break; 968b2167459SRichard Henderson 969b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 970aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 9716fd0c7bcSRichard Henderson tcg_gen_subi_i64(tmp, res, d_repl * 0x00010001u); 9726fd0c7bcSRichard Henderson tcg_gen_andc_i64(tmp, tmp, res); 9736fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, d_repl * 0x80008000u); 974b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 975b2167459SRichard Henderson break; 976b2167459SRichard Henderson 977b2167459SRichard Henderson case 4: /* SDC / NDC */ 9786fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x88888888u); 979b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 980b2167459SRichard Henderson break; 981b2167459SRichard Henderson 982b2167459SRichard Henderson case 6: /* SBC / NBC */ 9836fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80808080u); 984b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 985b2167459SRichard Henderson break; 986b2167459SRichard Henderson 987b2167459SRichard Henderson case 7: /* SHC / NHC */ 9886fd0c7bcSRichard Henderson tcg_gen_andi_i64(cb, cb, d_repl * 0x80008000u); 989b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 990b2167459SRichard Henderson break; 991b2167459SRichard Henderson 992b2167459SRichard Henderson default: 993b2167459SRichard Henderson g_assert_not_reached(); 994b2167459SRichard Henderson } 995b2167459SRichard Henderson if (cf & 1) { 996b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 997b2167459SRichard Henderson } 998b2167459SRichard Henderson 999b2167459SRichard Henderson return cond; 1000b2167459SRichard Henderson } 1001b2167459SRichard Henderson 10026fd0c7bcSRichard Henderson static TCGv_i64 get_carry(DisasContext *ctx, bool d, 10036fd0c7bcSRichard Henderson TCGv_i64 cb, TCGv_i64 cb_msb) 100472ca8753SRichard Henderson { 100572ca8753SRichard Henderson if (cond_need_ext(ctx, d)) { 1006aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 10076fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, cb, 32, 1); 100872ca8753SRichard Henderson return t; 100972ca8753SRichard Henderson } 101072ca8753SRichard Henderson return cb_msb; 101172ca8753SRichard Henderson } 101272ca8753SRichard Henderson 10136fd0c7bcSRichard Henderson static TCGv_i64 get_psw_carry(DisasContext *ctx, bool d) 101472ca8753SRichard Henderson { 101572ca8753SRichard Henderson return get_carry(ctx, d, cpu_psw_cb, cpu_psw_cb_msb); 101672ca8753SRichard Henderson } 101772ca8753SRichard Henderson 1018b2167459SRichard Henderson /* Compute signed overflow for addition. */ 10196fd0c7bcSRichard Henderson static TCGv_i64 do_add_sv(DisasContext *ctx, TCGv_i64 res, 10206fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1021b2167459SRichard Henderson { 1022aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1023aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1024b2167459SRichard Henderson 10256fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10266fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10276fd0c7bcSRichard Henderson tcg_gen_andc_i64(sv, sv, tmp); 1028b2167459SRichard Henderson 1029b2167459SRichard Henderson return sv; 1030b2167459SRichard Henderson } 1031b2167459SRichard Henderson 1032b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 10336fd0c7bcSRichard Henderson static TCGv_i64 do_sub_sv(DisasContext *ctx, TCGv_i64 res, 10346fd0c7bcSRichard Henderson TCGv_i64 in1, TCGv_i64 in2) 1035b2167459SRichard Henderson { 1036aac0f603SRichard Henderson TCGv_i64 sv = tcg_temp_new_i64(); 1037aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 1038b2167459SRichard Henderson 10396fd0c7bcSRichard Henderson tcg_gen_xor_i64(sv, res, in1); 10406fd0c7bcSRichard Henderson tcg_gen_xor_i64(tmp, in1, in2); 10416fd0c7bcSRichard Henderson tcg_gen_and_i64(sv, sv, tmp); 1042b2167459SRichard Henderson 1043b2167459SRichard Henderson return sv; 1044b2167459SRichard Henderson } 1045b2167459SRichard Henderson 10466fd0c7bcSRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 10476fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned shift, bool is_l, 1048faf97ba1SRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf, bool d) 1049b2167459SRichard Henderson { 10506fd0c7bcSRichard Henderson TCGv_i64 dest, cb, cb_msb, cb_cond, sv, tmp; 1051b2167459SRichard Henderson unsigned c = cf >> 1; 1052b2167459SRichard Henderson DisasCond cond; 1053b2167459SRichard Henderson 1054aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1055f764718dSRichard Henderson cb = NULL; 1056f764718dSRichard Henderson cb_msb = NULL; 1057bdcccc17SRichard Henderson cb_cond = NULL; 1058b2167459SRichard Henderson 1059b2167459SRichard Henderson if (shift) { 1060aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 10616fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, in1, shift); 1062b2167459SRichard Henderson in1 = tmp; 1063b2167459SRichard Henderson } 1064b2167459SRichard Henderson 1065b47a4a02SSven Schnelle if (!is_l || cond_need_cb(c)) { 1066aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1067aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1068bdcccc17SRichard Henderson 1069a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); 1070b2167459SRichard Henderson if (is_c) { 10716fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, 1072a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1073b2167459SRichard Henderson } 10746fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 10756fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1076bdcccc17SRichard Henderson if (cond_need_cb(c)) { 1077bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 1078b2167459SRichard Henderson } 1079b2167459SRichard Henderson } else { 10806fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 1081b2167459SRichard Henderson if (is_c) { 10826fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, get_psw_carry(ctx, d)); 1083b2167459SRichard Henderson } 1084b2167459SRichard Henderson } 1085b2167459SRichard Henderson 1086b2167459SRichard Henderson /* Compute signed overflow if required. */ 1087f764718dSRichard Henderson sv = NULL; 1088b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1089b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 1090b2167459SRichard Henderson if (is_tsv) { 1091b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 1092ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1093b2167459SRichard Henderson } 1094b2167459SRichard Henderson } 1095b2167459SRichard Henderson 1096b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1097a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, cb_cond, sv); 1098b2167459SRichard Henderson if (is_tc) { 1099aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11006fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1101ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1102b2167459SRichard Henderson } 1103b2167459SRichard Henderson 1104b2167459SRichard Henderson /* Write back the result. */ 1105b2167459SRichard Henderson if (!is_l) { 1106b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1107b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1108b2167459SRichard Henderson } 1109b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1110b2167459SRichard Henderson 1111b2167459SRichard Henderson /* Install the new nullification. */ 1112b2167459SRichard Henderson cond_free(&ctx->null_cond); 1113b2167459SRichard Henderson ctx->null_cond = cond; 1114b2167459SRichard Henderson } 1115b2167459SRichard Henderson 1116faf97ba1SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_d_sh *a, 11170c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 11180c982a28SRichard Henderson { 11196fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 11200c982a28SRichard Henderson 11210c982a28SRichard Henderson if (a->cf) { 11220c982a28SRichard Henderson nullify_over(ctx); 11230c982a28SRichard Henderson } 11240c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 11250c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1126faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, 1127faf97ba1SRichard Henderson is_tsv, is_tc, is_c, a->cf, a->d); 11280c982a28SRichard Henderson return nullify_end(ctx); 11290c982a28SRichard Henderson } 11300c982a28SRichard Henderson 11310588e061SRichard Henderson static bool do_add_imm(DisasContext *ctx, arg_rri_cf *a, 11320588e061SRichard Henderson bool is_tsv, bool is_tc) 11330588e061SRichard Henderson { 11346fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 11350588e061SRichard Henderson 11360588e061SRichard Henderson if (a->cf) { 11370588e061SRichard Henderson nullify_over(ctx); 11380588e061SRichard Henderson } 11396fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 11400588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 1141faf97ba1SRichard Henderson /* All ADDI conditions are 32-bit. */ 1142faf97ba1SRichard Henderson do_add(ctx, a->t, tcg_im, tcg_r2, 0, 0, is_tsv, is_tc, 0, a->cf, false); 11430588e061SRichard Henderson return nullify_end(ctx); 11440588e061SRichard Henderson } 11450588e061SRichard Henderson 11466fd0c7bcSRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 11476fd0c7bcSRichard Henderson TCGv_i64 in2, bool is_tsv, bool is_b, 114863c427c6SRichard Henderson bool is_tc, unsigned cf, bool d) 1149b2167459SRichard Henderson { 1150a4db4a78SRichard Henderson TCGv_i64 dest, sv, cb, cb_msb, tmp; 1151b2167459SRichard Henderson unsigned c = cf >> 1; 1152b2167459SRichard Henderson DisasCond cond; 1153b2167459SRichard Henderson 1154aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1155aac0f603SRichard Henderson cb = tcg_temp_new_i64(); 1156aac0f603SRichard Henderson cb_msb = tcg_temp_new_i64(); 1157b2167459SRichard Henderson 1158b2167459SRichard Henderson if (is_b) { 1159b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 11606fd0c7bcSRichard Henderson tcg_gen_not_i64(cb, in2); 1161a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, 1162a4db4a78SRichard Henderson get_psw_carry(ctx, d), ctx->zero); 1163a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); 11646fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, in1); 11656fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1166b2167459SRichard Henderson } else { 1167bdcccc17SRichard Henderson /* 1168bdcccc17SRichard Henderson * DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1169bdcccc17SRichard Henderson * operations by seeding the high word with 1 and subtracting. 1170bdcccc17SRichard Henderson */ 11716fd0c7bcSRichard Henderson TCGv_i64 one = tcg_constant_i64(1); 1172a4db4a78SRichard Henderson tcg_gen_sub2_i64(dest, cb_msb, in1, one, in2, ctx->zero); 11736fd0c7bcSRichard Henderson tcg_gen_eqv_i64(cb, in1, in2); 11746fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 1175b2167459SRichard Henderson } 1176b2167459SRichard Henderson 1177b2167459SRichard Henderson /* Compute signed overflow if required. */ 1178f764718dSRichard Henderson sv = NULL; 1179b47a4a02SSven Schnelle if (is_tsv || cond_need_sv(c)) { 1180b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1181b2167459SRichard Henderson if (is_tsv) { 1182ad75a51eSRichard Henderson gen_helper_tsv(tcg_env, sv); 1183b2167459SRichard Henderson } 1184b2167459SRichard Henderson } 1185b2167459SRichard Henderson 1186b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1187b2167459SRichard Henderson if (!is_b) { 11884fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1189b2167459SRichard Henderson } else { 1190a751eb31SRichard Henderson cond = do_cond(ctx, cf, d, dest, get_carry(ctx, d, cb, cb_msb), sv); 1191b2167459SRichard Henderson } 1192b2167459SRichard Henderson 1193b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1194b2167459SRichard Henderson if (is_tc) { 1195aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 11966fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1197ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1198b2167459SRichard Henderson } 1199b2167459SRichard Henderson 1200b2167459SRichard Henderson /* Write back the result. */ 1201b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1202b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1203b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1204b2167459SRichard Henderson 1205b2167459SRichard Henderson /* Install the new nullification. */ 1206b2167459SRichard Henderson cond_free(&ctx->null_cond); 1207b2167459SRichard Henderson ctx->null_cond = cond; 1208b2167459SRichard Henderson } 1209b2167459SRichard Henderson 121063c427c6SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12110c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 12120c982a28SRichard Henderson { 12136fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12140c982a28SRichard Henderson 12150c982a28SRichard Henderson if (a->cf) { 12160c982a28SRichard Henderson nullify_over(ctx); 12170c982a28SRichard Henderson } 12180c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12190c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 122063c427c6SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf, a->d); 12210c982a28SRichard Henderson return nullify_end(ctx); 12220c982a28SRichard Henderson } 12230c982a28SRichard Henderson 12240588e061SRichard Henderson static bool do_sub_imm(DisasContext *ctx, arg_rri_cf *a, bool is_tsv) 12250588e061SRichard Henderson { 12266fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 12270588e061SRichard Henderson 12280588e061SRichard Henderson if (a->cf) { 12290588e061SRichard Henderson nullify_over(ctx); 12300588e061SRichard Henderson } 12316fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 12320588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 123363c427c6SRichard Henderson /* All SUBI conditions are 32-bit. */ 123463c427c6SRichard Henderson do_sub(ctx, a->t, tcg_im, tcg_r2, is_tsv, 0, 0, a->cf, false); 12350588e061SRichard Henderson return nullify_end(ctx); 12360588e061SRichard Henderson } 12370588e061SRichard Henderson 12386fd0c7bcSRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12396fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d) 1240b2167459SRichard Henderson { 12416fd0c7bcSRichard Henderson TCGv_i64 dest, sv; 1242b2167459SRichard Henderson DisasCond cond; 1243b2167459SRichard Henderson 1244aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 12456fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 1246b2167459SRichard Henderson 1247b2167459SRichard Henderson /* Compute signed overflow if required. */ 1248f764718dSRichard Henderson sv = NULL; 1249b47a4a02SSven Schnelle if (cond_need_sv(cf >> 1)) { 1250b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1251b2167459SRichard Henderson } 1252b2167459SRichard Henderson 1253b2167459SRichard Henderson /* Form the condition for the compare. */ 12544fe9533aSRichard Henderson cond = do_sub_cond(ctx, cf, d, dest, in1, in2, sv); 1255b2167459SRichard Henderson 1256b2167459SRichard Henderson /* Clear. */ 12576fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 1258b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1259b2167459SRichard Henderson 1260b2167459SRichard Henderson /* Install the new nullification. */ 1261b2167459SRichard Henderson cond_free(&ctx->null_cond); 1262b2167459SRichard Henderson ctx->null_cond = cond; 1263b2167459SRichard Henderson } 1264b2167459SRichard Henderson 12656fd0c7bcSRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12666fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, 12676fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1268b2167459SRichard Henderson { 12696fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 1270b2167459SRichard Henderson 1271b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1272b2167459SRichard Henderson fn(dest, in1, in2); 1273b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1274b2167459SRichard Henderson 1275b2167459SRichard Henderson /* Install the new nullification. */ 1276b2167459SRichard Henderson cond_free(&ctx->null_cond); 1277b2167459SRichard Henderson if (cf) { 1278b5af8423SRichard Henderson ctx->null_cond = do_log_cond(ctx, cf, d, dest); 1279b2167459SRichard Henderson } 1280b2167459SRichard Henderson } 1281b2167459SRichard Henderson 1282fa8e3bedSRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf_d *a, 12836fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 12840c982a28SRichard Henderson { 12856fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 12860c982a28SRichard Henderson 12870c982a28SRichard Henderson if (a->cf) { 12880c982a28SRichard Henderson nullify_over(ctx); 12890c982a28SRichard Henderson } 12900c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12910c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 1292fa8e3bedSRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, fn); 12930c982a28SRichard Henderson return nullify_end(ctx); 12940c982a28SRichard Henderson } 12950c982a28SRichard Henderson 12966fd0c7bcSRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_i64 in1, 12976fd0c7bcSRichard Henderson TCGv_i64 in2, unsigned cf, bool d, bool is_tc, 12986fd0c7bcSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 1299b2167459SRichard Henderson { 13006fd0c7bcSRichard Henderson TCGv_i64 dest; 1301b2167459SRichard Henderson DisasCond cond; 1302b2167459SRichard Henderson 1303b2167459SRichard Henderson if (cf == 0) { 1304b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 1305b2167459SRichard Henderson fn(dest, in1, in2); 1306b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1307b2167459SRichard Henderson cond_free(&ctx->null_cond); 1308b2167459SRichard Henderson } else { 1309aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 1310b2167459SRichard Henderson fn(dest, in1, in2); 1311b2167459SRichard Henderson 131259963d8fSRichard Henderson cond = do_unit_cond(cf, d, dest, in1, in2); 1313b2167459SRichard Henderson 1314b2167459SRichard Henderson if (is_tc) { 1315aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 13166fd0c7bcSRichard Henderson tcg_gen_setcond_i64(cond.c, tmp, cond.a0, cond.a1); 1317ad75a51eSRichard Henderson gen_helper_tcond(tcg_env, tmp); 1318b2167459SRichard Henderson } 1319b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1320b2167459SRichard Henderson 1321b2167459SRichard Henderson cond_free(&ctx->null_cond); 1322b2167459SRichard Henderson ctx->null_cond = cond; 1323b2167459SRichard Henderson } 1324b2167459SRichard Henderson } 1325b2167459SRichard Henderson 132686f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 13278d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 13288d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 13298d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 13308d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 13316fd0c7bcSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_i64 base) 133286f8d05fSRichard Henderson { 133386f8d05fSRichard Henderson TCGv_ptr ptr; 13346fd0c7bcSRichard Henderson TCGv_i64 tmp; 133586f8d05fSRichard Henderson TCGv_i64 spc; 133686f8d05fSRichard Henderson 133786f8d05fSRichard Henderson if (sp != 0) { 13388d6ae7fbSRichard Henderson if (sp < 0) { 13398d6ae7fbSRichard Henderson sp = ~sp; 13408d6ae7fbSRichard Henderson } 13416fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 13428d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 13438d6ae7fbSRichard Henderson return spc; 134486f8d05fSRichard Henderson } 1345494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1346494737b7SRichard Henderson return cpu_srH; 1347494737b7SRichard Henderson } 134886f8d05fSRichard Henderson 134986f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 1350aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 13516fd0c7bcSRichard Henderson spc = tcg_temp_new_i64(); 135286f8d05fSRichard Henderson 1353698240d1SRichard Henderson /* Extract top 2 bits of the address, shift left 3 for uint64_t index. */ 13546fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, base, (ctx->tb_flags & PSW_W ? 64 : 32) - 5); 13556fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, 030); 13566fd0c7bcSRichard Henderson tcg_gen_trunc_i64_ptr(ptr, tmp); 135786f8d05fSRichard Henderson 1358ad75a51eSRichard Henderson tcg_gen_add_ptr(ptr, ptr, tcg_env); 135986f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 136086f8d05fSRichard Henderson 136186f8d05fSRichard Henderson return spc; 136286f8d05fSRichard Henderson } 136386f8d05fSRichard Henderson #endif 136486f8d05fSRichard Henderson 13656fd0c7bcSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_i64 *pgva, TCGv_i64 *pofs, 1366c53e401eSRichard Henderson unsigned rb, unsigned rx, int scale, int64_t disp, 136786f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 136886f8d05fSRichard Henderson { 13696fd0c7bcSRichard Henderson TCGv_i64 base = load_gpr(ctx, rb); 13706fd0c7bcSRichard Henderson TCGv_i64 ofs; 13716fd0c7bcSRichard Henderson TCGv_i64 addr; 137286f8d05fSRichard Henderson 1373f5b5c857SRichard Henderson set_insn_breg(ctx, rb); 1374f5b5c857SRichard Henderson 137586f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 137686f8d05fSRichard Henderson if (rx) { 1377aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13786fd0c7bcSRichard Henderson tcg_gen_shli_i64(ofs, cpu_gr[rx], scale); 13796fd0c7bcSRichard Henderson tcg_gen_add_i64(ofs, ofs, base); 138086f8d05fSRichard Henderson } else if (disp || modify) { 1381aac0f603SRichard Henderson ofs = tcg_temp_new_i64(); 13826fd0c7bcSRichard Henderson tcg_gen_addi_i64(ofs, base, disp); 138386f8d05fSRichard Henderson } else { 138486f8d05fSRichard Henderson ofs = base; 138586f8d05fSRichard Henderson } 138686f8d05fSRichard Henderson 138786f8d05fSRichard Henderson *pofs = ofs; 13886fd0c7bcSRichard Henderson *pgva = addr = tcg_temp_new_i64(); 1389d265360fSRichard Henderson tcg_gen_andi_i64(addr, modify <= 0 ? ofs : base, gva_offset_mask(ctx)); 1390698240d1SRichard Henderson #ifndef CONFIG_USER_ONLY 139186f8d05fSRichard Henderson if (!is_phys) { 1392d265360fSRichard Henderson tcg_gen_or_i64(addr, addr, space_select(ctx, sp, base)); 139386f8d05fSRichard Henderson } 139486f8d05fSRichard Henderson #endif 139586f8d05fSRichard Henderson } 139686f8d05fSRichard Henderson 139796d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 139896d6407fSRichard Henderson * < 0 for pre-modify, 139996d6407fSRichard Henderson * > 0 for post-modify, 140096d6407fSRichard Henderson * = 0 for no base register update. 140196d6407fSRichard Henderson */ 140296d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1403c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 140414776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 140596d6407fSRichard Henderson { 14066fd0c7bcSRichard Henderson TCGv_i64 ofs; 14076fd0c7bcSRichard Henderson TCGv_i64 addr; 140896d6407fSRichard Henderson 140996d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 141096d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 141196d6407fSRichard Henderson 141286f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 141317fe594cSRichard Henderson MMU_DISABLED(ctx)); 1414c1f55d97SRichard Henderson tcg_gen_qemu_ld_i32(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 141586f8d05fSRichard Henderson if (modify) { 141686f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 141796d6407fSRichard Henderson } 141896d6407fSRichard Henderson } 141996d6407fSRichard Henderson 142096d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1421c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 142214776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 142396d6407fSRichard Henderson { 14246fd0c7bcSRichard Henderson TCGv_i64 ofs; 14256fd0c7bcSRichard Henderson TCGv_i64 addr; 142696d6407fSRichard Henderson 142796d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 142896d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 142996d6407fSRichard Henderson 143086f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 143117fe594cSRichard Henderson MMU_DISABLED(ctx)); 1432217d1a5eSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 143386f8d05fSRichard Henderson if (modify) { 143486f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 143596d6407fSRichard Henderson } 143696d6407fSRichard Henderson } 143796d6407fSRichard Henderson 143896d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1439c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 144014776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 144196d6407fSRichard Henderson { 14426fd0c7bcSRichard Henderson TCGv_i64 ofs; 14436fd0c7bcSRichard Henderson TCGv_i64 addr; 144496d6407fSRichard Henderson 144596d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 144696d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 144796d6407fSRichard Henderson 144886f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 144917fe594cSRichard Henderson MMU_DISABLED(ctx)); 1450217d1a5eSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 145186f8d05fSRichard Henderson if (modify) { 145286f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 145396d6407fSRichard Henderson } 145496d6407fSRichard Henderson } 145596d6407fSRichard Henderson 145696d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1457c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 145814776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 145996d6407fSRichard Henderson { 14606fd0c7bcSRichard Henderson TCGv_i64 ofs; 14616fd0c7bcSRichard Henderson TCGv_i64 addr; 146296d6407fSRichard Henderson 146396d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 146496d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 146596d6407fSRichard Henderson 146686f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 146717fe594cSRichard Henderson MMU_DISABLED(ctx)); 1468217d1a5eSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop | UNALIGN(ctx)); 146986f8d05fSRichard Henderson if (modify) { 147086f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 147196d6407fSRichard Henderson } 147296d6407fSRichard Henderson } 147396d6407fSRichard Henderson 14741cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1475c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 147614776ab5STony Nguyen unsigned sp, int modify, MemOp mop) 147796d6407fSRichard Henderson { 14786fd0c7bcSRichard Henderson TCGv_i64 dest; 147996d6407fSRichard Henderson 148096d6407fSRichard Henderson nullify_over(ctx); 148196d6407fSRichard Henderson 148296d6407fSRichard Henderson if (modify == 0) { 148396d6407fSRichard Henderson /* No base register update. */ 148496d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 148596d6407fSRichard Henderson } else { 148696d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 1487aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 148896d6407fSRichard Henderson } 14896fd0c7bcSRichard Henderson do_load_64(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 149096d6407fSRichard Henderson save_gpr(ctx, rt, dest); 149196d6407fSRichard Henderson 14921cd012a5SRichard Henderson return nullify_end(ctx); 149396d6407fSRichard Henderson } 149496d6407fSRichard Henderson 1495740038d7SRichard Henderson static bool do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1496c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 149786f8d05fSRichard Henderson unsigned sp, int modify) 149896d6407fSRichard Henderson { 149996d6407fSRichard Henderson TCGv_i32 tmp; 150096d6407fSRichard Henderson 150196d6407fSRichard Henderson nullify_over(ctx); 150296d6407fSRichard Henderson 150396d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 150486f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 150596d6407fSRichard Henderson save_frw_i32(rt, tmp); 150696d6407fSRichard Henderson 150796d6407fSRichard Henderson if (rt == 0) { 1508ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 150996d6407fSRichard Henderson } 151096d6407fSRichard Henderson 1511740038d7SRichard Henderson return nullify_end(ctx); 151296d6407fSRichard Henderson } 151396d6407fSRichard Henderson 1514740038d7SRichard Henderson static bool trans_fldw(DisasContext *ctx, arg_ldst *a) 1515740038d7SRichard Henderson { 1516740038d7SRichard Henderson return do_floadw(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1517740038d7SRichard Henderson a->disp, a->sp, a->m); 1518740038d7SRichard Henderson } 1519740038d7SRichard Henderson 1520740038d7SRichard Henderson static bool do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1521c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 152286f8d05fSRichard Henderson unsigned sp, int modify) 152396d6407fSRichard Henderson { 152496d6407fSRichard Henderson TCGv_i64 tmp; 152596d6407fSRichard Henderson 152696d6407fSRichard Henderson nullify_over(ctx); 152796d6407fSRichard Henderson 152896d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 1529fc313c64SFrédéric Pétrot do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 153096d6407fSRichard Henderson save_frd(rt, tmp); 153196d6407fSRichard Henderson 153296d6407fSRichard Henderson if (rt == 0) { 1533ad75a51eSRichard Henderson gen_helper_loaded_fr0(tcg_env); 153496d6407fSRichard Henderson } 153596d6407fSRichard Henderson 1536740038d7SRichard Henderson return nullify_end(ctx); 1537740038d7SRichard Henderson } 1538740038d7SRichard Henderson 1539740038d7SRichard Henderson static bool trans_fldd(DisasContext *ctx, arg_ldst *a) 1540740038d7SRichard Henderson { 1541740038d7SRichard Henderson return do_floadd(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1542740038d7SRichard Henderson a->disp, a->sp, a->m); 154396d6407fSRichard Henderson } 154496d6407fSRichard Henderson 15451cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 1546c53e401eSRichard Henderson int64_t disp, unsigned sp, 154714776ab5STony Nguyen int modify, MemOp mop) 154896d6407fSRichard Henderson { 154996d6407fSRichard Henderson nullify_over(ctx); 15506fd0c7bcSRichard Henderson do_store_64(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 15511cd012a5SRichard Henderson return nullify_end(ctx); 155296d6407fSRichard Henderson } 155396d6407fSRichard Henderson 1554740038d7SRichard Henderson static bool do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1555c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 155686f8d05fSRichard Henderson unsigned sp, int modify) 155796d6407fSRichard Henderson { 155896d6407fSRichard Henderson TCGv_i32 tmp; 155996d6407fSRichard Henderson 156096d6407fSRichard Henderson nullify_over(ctx); 156196d6407fSRichard Henderson 156296d6407fSRichard Henderson tmp = load_frw_i32(rt); 156386f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 156496d6407fSRichard Henderson 1565740038d7SRichard Henderson return nullify_end(ctx); 156696d6407fSRichard Henderson } 156796d6407fSRichard Henderson 1568740038d7SRichard Henderson static bool trans_fstw(DisasContext *ctx, arg_ldst *a) 1569740038d7SRichard Henderson { 1570740038d7SRichard Henderson return do_fstorew(ctx, a->t, a->b, a->x, a->scale ? 2 : 0, 1571740038d7SRichard Henderson a->disp, a->sp, a->m); 1572740038d7SRichard Henderson } 1573740038d7SRichard Henderson 1574740038d7SRichard Henderson static bool do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1575c53e401eSRichard Henderson unsigned rx, int scale, int64_t disp, 157686f8d05fSRichard Henderson unsigned sp, int modify) 157796d6407fSRichard Henderson { 157896d6407fSRichard Henderson TCGv_i64 tmp; 157996d6407fSRichard Henderson 158096d6407fSRichard Henderson nullify_over(ctx); 158196d6407fSRichard Henderson 158296d6407fSRichard Henderson tmp = load_frd(rt); 1583fc313c64SFrédéric Pétrot do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUQ); 158496d6407fSRichard Henderson 1585740038d7SRichard Henderson return nullify_end(ctx); 1586740038d7SRichard Henderson } 1587740038d7SRichard Henderson 1588740038d7SRichard Henderson static bool trans_fstd(DisasContext *ctx, arg_ldst *a) 1589740038d7SRichard Henderson { 1590740038d7SRichard Henderson return do_fstored(ctx, a->t, a->b, a->x, a->scale ? 3 : 0, 1591740038d7SRichard Henderson a->disp, a->sp, a->m); 159296d6407fSRichard Henderson } 159396d6407fSRichard Henderson 15941ca74648SRichard Henderson static bool do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1595ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1596ebe9383cSRichard Henderson { 1597ebe9383cSRichard Henderson TCGv_i32 tmp; 1598ebe9383cSRichard Henderson 1599ebe9383cSRichard Henderson nullify_over(ctx); 1600ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1601ebe9383cSRichard Henderson 1602ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1603ebe9383cSRichard Henderson 1604ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 16051ca74648SRichard Henderson return nullify_end(ctx); 1606ebe9383cSRichard Henderson } 1607ebe9383cSRichard Henderson 16081ca74648SRichard Henderson static bool do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1609ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1610ebe9383cSRichard Henderson { 1611ebe9383cSRichard Henderson TCGv_i32 dst; 1612ebe9383cSRichard Henderson TCGv_i64 src; 1613ebe9383cSRichard Henderson 1614ebe9383cSRichard Henderson nullify_over(ctx); 1615ebe9383cSRichard Henderson src = load_frd(ra); 1616ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1617ebe9383cSRichard Henderson 1618ad75a51eSRichard Henderson func(dst, tcg_env, src); 1619ebe9383cSRichard Henderson 1620ebe9383cSRichard Henderson save_frw_i32(rt, dst); 16211ca74648SRichard Henderson return nullify_end(ctx); 1622ebe9383cSRichard Henderson } 1623ebe9383cSRichard Henderson 16241ca74648SRichard Henderson static bool do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1625ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1626ebe9383cSRichard Henderson { 1627ebe9383cSRichard Henderson TCGv_i64 tmp; 1628ebe9383cSRichard Henderson 1629ebe9383cSRichard Henderson nullify_over(ctx); 1630ebe9383cSRichard Henderson tmp = load_frd0(ra); 1631ebe9383cSRichard Henderson 1632ad75a51eSRichard Henderson func(tmp, tcg_env, tmp); 1633ebe9383cSRichard Henderson 1634ebe9383cSRichard Henderson save_frd(rt, tmp); 16351ca74648SRichard Henderson return nullify_end(ctx); 1636ebe9383cSRichard Henderson } 1637ebe9383cSRichard Henderson 16381ca74648SRichard Henderson static bool do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1639ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1640ebe9383cSRichard Henderson { 1641ebe9383cSRichard Henderson TCGv_i32 src; 1642ebe9383cSRichard Henderson TCGv_i64 dst; 1643ebe9383cSRichard Henderson 1644ebe9383cSRichard Henderson nullify_over(ctx); 1645ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1646ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1647ebe9383cSRichard Henderson 1648ad75a51eSRichard Henderson func(dst, tcg_env, src); 1649ebe9383cSRichard Henderson 1650ebe9383cSRichard Henderson save_frd(rt, dst); 16511ca74648SRichard Henderson return nullify_end(ctx); 1652ebe9383cSRichard Henderson } 1653ebe9383cSRichard Henderson 16541ca74648SRichard Henderson static bool do_fop_weww(DisasContext *ctx, unsigned rt, 1655ebe9383cSRichard Henderson unsigned ra, unsigned rb, 165631234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1657ebe9383cSRichard Henderson { 1658ebe9383cSRichard Henderson TCGv_i32 a, b; 1659ebe9383cSRichard Henderson 1660ebe9383cSRichard Henderson nullify_over(ctx); 1661ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1662ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1663ebe9383cSRichard Henderson 1664ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1665ebe9383cSRichard Henderson 1666ebe9383cSRichard Henderson save_frw_i32(rt, a); 16671ca74648SRichard Henderson return nullify_end(ctx); 1668ebe9383cSRichard Henderson } 1669ebe9383cSRichard Henderson 16701ca74648SRichard Henderson static bool do_fop_dedd(DisasContext *ctx, unsigned rt, 1671ebe9383cSRichard Henderson unsigned ra, unsigned rb, 167231234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1673ebe9383cSRichard Henderson { 1674ebe9383cSRichard Henderson TCGv_i64 a, b; 1675ebe9383cSRichard Henderson 1676ebe9383cSRichard Henderson nullify_over(ctx); 1677ebe9383cSRichard Henderson a = load_frd0(ra); 1678ebe9383cSRichard Henderson b = load_frd0(rb); 1679ebe9383cSRichard Henderson 1680ad75a51eSRichard Henderson func(a, tcg_env, a, b); 1681ebe9383cSRichard Henderson 1682ebe9383cSRichard Henderson save_frd(rt, a); 16831ca74648SRichard Henderson return nullify_end(ctx); 1684ebe9383cSRichard Henderson } 1685ebe9383cSRichard Henderson 168698cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 168798cd9ca7SRichard Henderson have already had nullification handled. */ 1688c53e401eSRichard Henderson static bool do_dbranch(DisasContext *ctx, uint64_t dest, 168998cd9ca7SRichard Henderson unsigned link, bool is_n) 169098cd9ca7SRichard Henderson { 169198cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 169298cd9ca7SRichard Henderson if (link != 0) { 1693741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 169498cd9ca7SRichard Henderson } 169598cd9ca7SRichard Henderson ctx->iaoq_n = dest; 169698cd9ca7SRichard Henderson if (is_n) { 169798cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 169898cd9ca7SRichard Henderson } 169998cd9ca7SRichard Henderson } else { 170098cd9ca7SRichard Henderson nullify_over(ctx); 170198cd9ca7SRichard Henderson 170298cd9ca7SRichard Henderson if (link != 0) { 1703741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 170498cd9ca7SRichard Henderson } 170598cd9ca7SRichard Henderson 170698cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 170798cd9ca7SRichard Henderson nullify_set(ctx, 0); 170898cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 170998cd9ca7SRichard Henderson } else { 171098cd9ca7SRichard Henderson nullify_set(ctx, is_n); 171198cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 171298cd9ca7SRichard Henderson } 171398cd9ca7SRichard Henderson 171431234768SRichard Henderson nullify_end(ctx); 171598cd9ca7SRichard Henderson 171698cd9ca7SRichard Henderson nullify_set(ctx, 0); 171798cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 171831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 171998cd9ca7SRichard Henderson } 172001afb7beSRichard Henderson return true; 172198cd9ca7SRichard Henderson } 172298cd9ca7SRichard Henderson 172398cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 172498cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 1725c53e401eSRichard Henderson static bool do_cbranch(DisasContext *ctx, int64_t disp, bool is_n, 172698cd9ca7SRichard Henderson DisasCond *cond) 172798cd9ca7SRichard Henderson { 1728c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, disp); 172998cd9ca7SRichard Henderson TCGLabel *taken = NULL; 173098cd9ca7SRichard Henderson TCGCond c = cond->c; 173198cd9ca7SRichard Henderson bool n; 173298cd9ca7SRichard Henderson 173398cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 173498cd9ca7SRichard Henderson 173598cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 173698cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 173701afb7beSRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 173898cd9ca7SRichard Henderson } 173998cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 174001afb7beSRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 174198cd9ca7SRichard Henderson } 174298cd9ca7SRichard Henderson 174398cd9ca7SRichard Henderson taken = gen_new_label(); 17446fd0c7bcSRichard Henderson tcg_gen_brcond_i64(c, cond->a0, cond->a1, taken); 174598cd9ca7SRichard Henderson cond_free(cond); 174698cd9ca7SRichard Henderson 174798cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 174898cd9ca7SRichard Henderson n = is_n && disp < 0; 174998cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 175098cd9ca7SRichard Henderson nullify_set(ctx, 0); 1751a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 175298cd9ca7SRichard Henderson } else { 175398cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 175498cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 175598cd9ca7SRichard Henderson ctx->null_lab = NULL; 175698cd9ca7SRichard Henderson } 175798cd9ca7SRichard Henderson nullify_set(ctx, n); 1758c301f34eSRichard Henderson if (ctx->iaoq_n == -1) { 1759c301f34eSRichard Henderson /* The temporary iaoq_n_var died at the branch above. 1760c301f34eSRichard Henderson Regenerate it here instead of saving it. */ 17616fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 1762c301f34eSRichard Henderson } 1763a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 176498cd9ca7SRichard Henderson } 176598cd9ca7SRichard Henderson 176698cd9ca7SRichard Henderson gen_set_label(taken); 176798cd9ca7SRichard Henderson 176898cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 176998cd9ca7SRichard Henderson n = is_n && disp >= 0; 177098cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 177198cd9ca7SRichard Henderson nullify_set(ctx, 0); 1772a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, dest, dest + 4); 177398cd9ca7SRichard Henderson } else { 177498cd9ca7SRichard Henderson nullify_set(ctx, n); 1775a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 177698cd9ca7SRichard Henderson } 177798cd9ca7SRichard Henderson 177898cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 177998cd9ca7SRichard Henderson if (ctx->null_lab) { 178098cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 178198cd9ca7SRichard Henderson ctx->null_lab = NULL; 178231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 178398cd9ca7SRichard Henderson } else { 178431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 178598cd9ca7SRichard Henderson } 178601afb7beSRichard Henderson return true; 178798cd9ca7SRichard Henderson } 178898cd9ca7SRichard Henderson 178998cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 179098cd9ca7SRichard Henderson nullification of the branch itself. */ 17916fd0c7bcSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_i64 dest, 179298cd9ca7SRichard Henderson unsigned link, bool is_n) 179398cd9ca7SRichard Henderson { 17946fd0c7bcSRichard Henderson TCGv_i64 a0, a1, next, tmp; 179598cd9ca7SRichard Henderson TCGCond c; 179698cd9ca7SRichard Henderson 179798cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 179898cd9ca7SRichard Henderson 179998cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 180098cd9ca7SRichard Henderson if (link != 0) { 1801741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 180298cd9ca7SRichard Henderson } 1803aac0f603SRichard Henderson next = tcg_temp_new_i64(); 18046fd0c7bcSRichard Henderson tcg_gen_mov_i64(next, dest); 180598cd9ca7SRichard Henderson if (is_n) { 1806c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1807a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, next); 18086fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, next, 4); 1809a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 1810c301f34eSRichard Henderson nullify_set(ctx, 0); 181131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 181201afb7beSRichard Henderson return true; 1813c301f34eSRichard Henderson } 181498cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 181598cd9ca7SRichard Henderson } 1816c301f34eSRichard Henderson ctx->iaoq_n = -1; 1817c301f34eSRichard Henderson ctx->iaoq_n_var = next; 181898cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 181998cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 182098cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 18214137cb83SRichard Henderson tracepoint in effect). Since the goto_ptr that we must use 182298cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 182398cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 182498cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 182598cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 182698cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 182798cd9ca7SRichard Henderson 182898cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 182998cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 183098cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 1831a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, dest); 1832aac0f603SRichard Henderson next = tcg_temp_new_i64(); 18336fd0c7bcSRichard Henderson tcg_gen_addi_i64(next, dest, 4); 1834a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, next); 183598cd9ca7SRichard Henderson 183698cd9ca7SRichard Henderson nullify_over(ctx); 183798cd9ca7SRichard Henderson if (link != 0) { 18389a91dd84SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 183998cd9ca7SRichard Henderson } 18407f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 184101afb7beSRichard Henderson return nullify_end(ctx); 184298cd9ca7SRichard Henderson } else { 184398cd9ca7SRichard Henderson c = ctx->null_cond.c; 184498cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 184598cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 184698cd9ca7SRichard Henderson 1847aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 1848aac0f603SRichard Henderson next = tcg_temp_new_i64(); 184998cd9ca7SRichard Henderson 1850741322f4SRichard Henderson copy_iaoq_entry(ctx, tmp, ctx->iaoq_n, ctx->iaoq_n_var); 18516fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, next, a0, a1, tmp, dest); 185298cd9ca7SRichard Henderson ctx->iaoq_n = -1; 185398cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 185498cd9ca7SRichard Henderson 185598cd9ca7SRichard Henderson if (link != 0) { 18566fd0c7bcSRichard Henderson tcg_gen_movcond_i64(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 185798cd9ca7SRichard Henderson } 185898cd9ca7SRichard Henderson 185998cd9ca7SRichard Henderson if (is_n) { 186098cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 186198cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 186298cd9ca7SRichard Henderson to the branch. */ 18636fd0c7bcSRichard Henderson tcg_gen_setcond_i64(tcg_invert_cond(c), cpu_psw_n, a0, a1); 186498cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 186598cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 186698cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 186798cd9ca7SRichard Henderson } else { 186898cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 186998cd9ca7SRichard Henderson } 187098cd9ca7SRichard Henderson } 187101afb7beSRichard Henderson return true; 187298cd9ca7SRichard Henderson } 187398cd9ca7SRichard Henderson 1874660eefe1SRichard Henderson /* Implement 1875660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1876660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1877660eefe1SRichard Henderson * else 1878660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1879660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1880660eefe1SRichard Henderson */ 18816fd0c7bcSRichard Henderson static TCGv_i64 do_ibranch_priv(DisasContext *ctx, TCGv_i64 offset) 1882660eefe1SRichard Henderson { 18836fd0c7bcSRichard Henderson TCGv_i64 dest; 1884660eefe1SRichard Henderson switch (ctx->privilege) { 1885660eefe1SRichard Henderson case 0: 1886660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 1887660eefe1SRichard Henderson return offset; 1888660eefe1SRichard Henderson case 3: 1889993119feSRichard Henderson /* Privilege 3 is minimum and is never allowed to increase. */ 1890aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18916fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, offset, 3); 1892660eefe1SRichard Henderson break; 1893660eefe1SRichard Henderson default: 1894aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 18956fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, offset, -4); 18966fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, ctx->privilege); 18976fd0c7bcSRichard Henderson tcg_gen_movcond_i64(TCG_COND_GTU, dest, dest, offset, dest, offset); 1898660eefe1SRichard Henderson break; 1899660eefe1SRichard Henderson } 1900660eefe1SRichard Henderson return dest; 1901660eefe1SRichard Henderson } 1902660eefe1SRichard Henderson 1903ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 19047ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 19057ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 19067ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 19077ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 19087ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 19097ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 19107ad439dfSRichard Henderson aforementioned BE. */ 191131234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 19127ad439dfSRichard Henderson { 19136fd0c7bcSRichard Henderson TCGv_i64 tmp; 1914a0180973SRichard Henderson 19157ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 19167ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 19178b81968cSMichael Tokarev next insn within the privileged page. */ 19187ad439dfSRichard Henderson switch (ctx->null_cond.c) { 19197ad439dfSRichard Henderson case TCG_COND_NEVER: 19207ad439dfSRichard Henderson break; 19217ad439dfSRichard Henderson case TCG_COND_ALWAYS: 19226fd0c7bcSRichard Henderson tcg_gen_movi_i64(cpu_psw_n, 0); 19237ad439dfSRichard Henderson goto do_sigill; 19247ad439dfSRichard Henderson default: 19257ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 19267ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 19277ad439dfSRichard Henderson g_assert_not_reached(); 19287ad439dfSRichard Henderson } 19297ad439dfSRichard Henderson 19307ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 19317ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 19327ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 19337ad439dfSRichard Henderson under such conditions. */ 19347ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 19357ad439dfSRichard Henderson goto do_sigill; 19367ad439dfSRichard Henderson } 19377ad439dfSRichard Henderson 1938ebd0e151SRichard Henderson switch (ctx->iaoq_f & -4) { 19397ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 19402986721dSRichard Henderson gen_excp_1(EXCP_IMP); 194131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 194231234768SRichard Henderson break; 19437ad439dfSRichard Henderson 19447ad439dfSRichard Henderson case 0xb0: /* LWS */ 19457ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 194631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 194731234768SRichard Henderson break; 19487ad439dfSRichard Henderson 19497ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 19506fd0c7bcSRichard Henderson tcg_gen_st_i64(cpu_gr[26], tcg_env, offsetof(CPUHPPAState, cr[27])); 1951aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 19526fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_gr[31], 3); 1953a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 19546fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 1955a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 195631234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 195731234768SRichard Henderson break; 19587ad439dfSRichard Henderson 19597ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 19607ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 196131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 196231234768SRichard Henderson break; 19637ad439dfSRichard Henderson 19647ad439dfSRichard Henderson default: 19657ad439dfSRichard Henderson do_sigill: 19662986721dSRichard Henderson gen_excp_1(EXCP_ILL); 196731234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 196831234768SRichard Henderson break; 19697ad439dfSRichard Henderson } 19707ad439dfSRichard Henderson } 1971ba1d0b44SRichard Henderson #endif 19727ad439dfSRichard Henderson 1973deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 1974b2167459SRichard Henderson { 1975b2167459SRichard Henderson cond_free(&ctx->null_cond); 197631234768SRichard Henderson return true; 1977b2167459SRichard Henderson } 1978b2167459SRichard Henderson 197940f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 198098a9cb79SRichard Henderson { 198131234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 198298a9cb79SRichard Henderson } 198398a9cb79SRichard Henderson 1984e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 198598a9cb79SRichard Henderson { 198698a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 198798a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 198898a9cb79SRichard Henderson 198998a9cb79SRichard Henderson cond_free(&ctx->null_cond); 199031234768SRichard Henderson return true; 199198a9cb79SRichard Henderson } 199298a9cb79SRichard Henderson 1993c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 199498a9cb79SRichard Henderson { 1995c603e14aSRichard Henderson unsigned rt = a->t; 19966fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, rt); 19976fd0c7bcSRichard Henderson tcg_gen_movi_i64(tmp, ctx->iaoq_f); 199898a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 199998a9cb79SRichard Henderson 200098a9cb79SRichard Henderson cond_free(&ctx->null_cond); 200131234768SRichard Henderson return true; 200298a9cb79SRichard Henderson } 200398a9cb79SRichard Henderson 2004c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 200598a9cb79SRichard Henderson { 2006c603e14aSRichard Henderson unsigned rt = a->t; 2007c603e14aSRichard Henderson unsigned rs = a->sp; 200833423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 200998a9cb79SRichard Henderson 201033423472SRichard Henderson load_spr(ctx, t0, rs); 201133423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 201233423472SRichard Henderson 2013967662cdSRichard Henderson save_gpr(ctx, rt, t0); 201498a9cb79SRichard Henderson 201598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 201631234768SRichard Henderson return true; 201798a9cb79SRichard Henderson } 201898a9cb79SRichard Henderson 2019c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 202098a9cb79SRichard Henderson { 2021c603e14aSRichard Henderson unsigned rt = a->t; 2022c603e14aSRichard Henderson unsigned ctl = a->r; 20236fd0c7bcSRichard Henderson TCGv_i64 tmp; 202498a9cb79SRichard Henderson 202598a9cb79SRichard Henderson switch (ctl) { 202635136a77SRichard Henderson case CR_SAR: 2027c603e14aSRichard Henderson if (a->e == 0) { 202898a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 202998a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 20306fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 203198a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 203235136a77SRichard Henderson goto done; 203398a9cb79SRichard Henderson } 203498a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 203535136a77SRichard Henderson goto done; 203635136a77SRichard Henderson case CR_IT: /* Interval Timer */ 203735136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 203835136a77SRichard Henderson nullify_over(ctx); 203998a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2040dfd1b812SRichard Henderson if (translator_io_start(&ctx->base)) { 204149c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 204231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 204349c29d6cSRichard Henderson } else { 204449c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 204549c29d6cSRichard Henderson } 204698a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 204731234768SRichard Henderson return nullify_end(ctx); 204898a9cb79SRichard Henderson case 26: 204998a9cb79SRichard Henderson case 27: 205098a9cb79SRichard Henderson break; 205198a9cb79SRichard Henderson default: 205298a9cb79SRichard Henderson /* All other control registers are privileged. */ 205335136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 205435136a77SRichard Henderson break; 205598a9cb79SRichard Henderson } 205698a9cb79SRichard Henderson 2057aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20586fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 205935136a77SRichard Henderson save_gpr(ctx, rt, tmp); 206035136a77SRichard Henderson 206135136a77SRichard Henderson done: 206298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 206331234768SRichard Henderson return true; 206498a9cb79SRichard Henderson } 206598a9cb79SRichard Henderson 2066c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 206733423472SRichard Henderson { 2068c603e14aSRichard Henderson unsigned rr = a->r; 2069c603e14aSRichard Henderson unsigned rs = a->sp; 2070967662cdSRichard Henderson TCGv_i64 tmp; 207133423472SRichard Henderson 207233423472SRichard Henderson if (rs >= 5) { 207333423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 207433423472SRichard Henderson } 207533423472SRichard Henderson nullify_over(ctx); 207633423472SRichard Henderson 2077967662cdSRichard Henderson tmp = tcg_temp_new_i64(); 2078967662cdSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, rr), 32); 207933423472SRichard Henderson 208033423472SRichard Henderson if (rs >= 4) { 2081967662cdSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, sr[rs])); 2082494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 208333423472SRichard Henderson } else { 2084967662cdSRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], tmp); 208533423472SRichard Henderson } 208633423472SRichard Henderson 208731234768SRichard Henderson return nullify_end(ctx); 208833423472SRichard Henderson } 208933423472SRichard Henderson 2090c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 209198a9cb79SRichard Henderson { 2092c603e14aSRichard Henderson unsigned ctl = a->t; 20936fd0c7bcSRichard Henderson TCGv_i64 reg; 20946fd0c7bcSRichard Henderson TCGv_i64 tmp; 209598a9cb79SRichard Henderson 209635136a77SRichard Henderson if (ctl == CR_SAR) { 20974845f015SSven Schnelle reg = load_gpr(ctx, a->r); 2098aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 20996fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, reg, ctx->is_pa20 ? 63 : 31); 210098a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 210198a9cb79SRichard Henderson 210298a9cb79SRichard Henderson cond_free(&ctx->null_cond); 210331234768SRichard Henderson return true; 210498a9cb79SRichard Henderson } 210598a9cb79SRichard Henderson 210635136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 210735136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 210835136a77SRichard Henderson 2109c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 211035136a77SRichard Henderson nullify_over(ctx); 21114c34bab0SHelge Deller 21124c34bab0SHelge Deller if (ctx->is_pa20) { 21134845f015SSven Schnelle reg = load_gpr(ctx, a->r); 21144c34bab0SHelge Deller } else { 21154c34bab0SHelge Deller reg = tcg_temp_new_i64(); 21164c34bab0SHelge Deller tcg_gen_ext32u_i64(reg, load_gpr(ctx, a->r)); 21174c34bab0SHelge Deller } 21184845f015SSven Schnelle 211935136a77SRichard Henderson switch (ctl) { 212035136a77SRichard Henderson case CR_IT: 2121ad75a51eSRichard Henderson gen_helper_write_interval_timer(tcg_env, reg); 212235136a77SRichard Henderson break; 21234f5f2548SRichard Henderson case CR_EIRR: 2124ad75a51eSRichard Henderson gen_helper_write_eirr(tcg_env, reg); 21254f5f2548SRichard Henderson break; 21264f5f2548SRichard Henderson case CR_EIEM: 2127ad75a51eSRichard Henderson gen_helper_write_eiem(tcg_env, reg); 212831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 21294f5f2548SRichard Henderson break; 21304f5f2548SRichard Henderson 213135136a77SRichard Henderson case CR_IIASQ: 213235136a77SRichard Henderson case CR_IIAOQ: 213335136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 213435136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 2135aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 21366fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, 213735136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 21386fd0c7bcSRichard Henderson tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 21396fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, 214035136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 214135136a77SRichard Henderson break; 214235136a77SRichard Henderson 2143d5de20bdSSven Schnelle case CR_PID1: 2144d5de20bdSSven Schnelle case CR_PID2: 2145d5de20bdSSven Schnelle case CR_PID3: 2146d5de20bdSSven Schnelle case CR_PID4: 21476fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 2148d5de20bdSSven Schnelle #ifndef CONFIG_USER_ONLY 2149ad75a51eSRichard Henderson gen_helper_change_prot_id(tcg_env); 2150d5de20bdSSven Schnelle #endif 2151d5de20bdSSven Schnelle break; 2152d5de20bdSSven Schnelle 215335136a77SRichard Henderson default: 21546fd0c7bcSRichard Henderson tcg_gen_st_i64(reg, tcg_env, offsetof(CPUHPPAState, cr[ctl])); 215535136a77SRichard Henderson break; 215635136a77SRichard Henderson } 215731234768SRichard Henderson return nullify_end(ctx); 21584f5f2548SRichard Henderson #endif 215935136a77SRichard Henderson } 216035136a77SRichard Henderson 2161c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 216298a9cb79SRichard Henderson { 2163aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 216498a9cb79SRichard Henderson 21656fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, load_gpr(ctx, a->r)); 21666fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ctx->is_pa20 ? 63 : 31); 216798a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 216898a9cb79SRichard Henderson 216998a9cb79SRichard Henderson cond_free(&ctx->null_cond); 217031234768SRichard Henderson return true; 217198a9cb79SRichard Henderson } 217298a9cb79SRichard Henderson 2173e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 217498a9cb79SRichard Henderson { 21756fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->t); 217698a9cb79SRichard Henderson 21772330504cSHelge Deller #ifdef CONFIG_USER_ONLY 21782330504cSHelge Deller /* We don't implement space registers in user mode. */ 21796fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 21802330504cSHelge Deller #else 2181967662cdSRichard Henderson tcg_gen_mov_i64(dest, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 2182967662cdSRichard Henderson tcg_gen_shri_i64(dest, dest, 32); 21832330504cSHelge Deller #endif 2184e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 218598a9cb79SRichard Henderson 218698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 218731234768SRichard Henderson return true; 218898a9cb79SRichard Henderson } 218998a9cb79SRichard Henderson 2190e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2191e36f27efSRichard Henderson { 21927b2d70a1SHelge Deller #ifdef CONFIG_USER_ONLY 2193e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 21947b2d70a1SHelge Deller #else 21956fd0c7bcSRichard Henderson TCGv_i64 tmp; 2196e1b5a5edSRichard Henderson 21977b2d70a1SHelge Deller /* HP-UX 11i and HP ODE use rsm for read-access to PSW */ 21987b2d70a1SHelge Deller if (a->i) { 21997b2d70a1SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 22007b2d70a1SHelge Deller } 22017b2d70a1SHelge Deller 2202e1b5a5edSRichard Henderson nullify_over(ctx); 2203e1b5a5edSRichard Henderson 2204aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22056fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 22066fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, ~a->i); 2207ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2208e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2209e1b5a5edSRichard Henderson 2210e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 221131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 221231234768SRichard Henderson return nullify_end(ctx); 2213e36f27efSRichard Henderson #endif 2214e1b5a5edSRichard Henderson } 2215e1b5a5edSRichard Henderson 2216e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2217e1b5a5edSRichard Henderson { 2218e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2219e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 22206fd0c7bcSRichard Henderson TCGv_i64 tmp; 2221e1b5a5edSRichard Henderson 2222e1b5a5edSRichard Henderson nullify_over(ctx); 2223e1b5a5edSRichard Henderson 2224aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 22256fd0c7bcSRichard Henderson tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPUHPPAState, psw)); 22266fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, a->i); 2227ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, tmp); 2228e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2229e1b5a5edSRichard Henderson 2230e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 223131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 223231234768SRichard Henderson return nullify_end(ctx); 2233e36f27efSRichard Henderson #endif 2234e1b5a5edSRichard Henderson } 2235e1b5a5edSRichard Henderson 2236c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2237e1b5a5edSRichard Henderson { 2238e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2239c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 22406fd0c7bcSRichard Henderson TCGv_i64 tmp, reg; 2241e1b5a5edSRichard Henderson nullify_over(ctx); 2242e1b5a5edSRichard Henderson 2243c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2244aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 2245ad75a51eSRichard Henderson gen_helper_swap_system_mask(tmp, tcg_env, reg); 2246e1b5a5edSRichard Henderson 2247e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 224831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 224931234768SRichard Henderson return nullify_end(ctx); 2250c603e14aSRichard Henderson #endif 2251e1b5a5edSRichard Henderson } 2252f49b3537SRichard Henderson 2253e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2254f49b3537SRichard Henderson { 2255f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2256e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2257f49b3537SRichard Henderson nullify_over(ctx); 2258f49b3537SRichard Henderson 2259e36f27efSRichard Henderson if (rfi_r) { 2260ad75a51eSRichard Henderson gen_helper_rfi_r(tcg_env); 2261f49b3537SRichard Henderson } else { 2262ad75a51eSRichard Henderson gen_helper_rfi(tcg_env); 2263f49b3537SRichard Henderson } 226431234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 226507ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 226631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2267f49b3537SRichard Henderson 226831234768SRichard Henderson return nullify_end(ctx); 2269e36f27efSRichard Henderson #endif 2270f49b3537SRichard Henderson } 22716210db05SHelge Deller 2272e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2273e36f27efSRichard Henderson { 2274e36f27efSRichard Henderson return do_rfi(ctx, false); 2275e36f27efSRichard Henderson } 2276e36f27efSRichard Henderson 2277e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2278e36f27efSRichard Henderson { 2279e36f27efSRichard Henderson return do_rfi(ctx, true); 2280e36f27efSRichard Henderson } 2281e36f27efSRichard Henderson 228296927adbSRichard Henderson static bool trans_halt(DisasContext *ctx, arg_halt *a) 22836210db05SHelge Deller { 22846210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 228596927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 22866210db05SHelge Deller nullify_over(ctx); 2287ad75a51eSRichard Henderson gen_helper_halt(tcg_env); 228831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 228931234768SRichard Henderson return nullify_end(ctx); 229096927adbSRichard Henderson #endif 22916210db05SHelge Deller } 229296927adbSRichard Henderson 229396927adbSRichard Henderson static bool trans_reset(DisasContext *ctx, arg_reset *a) 229496927adbSRichard Henderson { 229596927adbSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 229696927adbSRichard Henderson #ifndef CONFIG_USER_ONLY 229796927adbSRichard Henderson nullify_over(ctx); 2298ad75a51eSRichard Henderson gen_helper_reset(tcg_env); 229996927adbSRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 230096927adbSRichard Henderson return nullify_end(ctx); 230196927adbSRichard Henderson #endif 230296927adbSRichard Henderson } 2303e1b5a5edSRichard Henderson 23044a4554c6SHelge Deller static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a) 23054a4554c6SHelge Deller { 23064a4554c6SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 23074a4554c6SHelge Deller #ifndef CONFIG_USER_ONLY 23084a4554c6SHelge Deller nullify_over(ctx); 2309ad75a51eSRichard Henderson gen_helper_getshadowregs(tcg_env); 23104a4554c6SHelge Deller return nullify_end(ctx); 23114a4554c6SHelge Deller #endif 23124a4554c6SHelge Deller } 23134a4554c6SHelge Deller 2314deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 231598a9cb79SRichard Henderson { 2316deee69a1SRichard Henderson if (a->m) { 23176fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, a->b); 23186fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->b); 23196fd0c7bcSRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->x); 232098a9cb79SRichard Henderson 232198a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 23226fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, src1, src2); 2323deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2324deee69a1SRichard Henderson } 232598a9cb79SRichard Henderson cond_free(&ctx->null_cond); 232631234768SRichard Henderson return true; 232798a9cb79SRichard Henderson } 232898a9cb79SRichard Henderson 2329deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 233098a9cb79SRichard Henderson { 23316fd0c7bcSRichard Henderson TCGv_i64 dest, ofs; 2332eed14219SRichard Henderson TCGv_i32 level, want; 23336fd0c7bcSRichard Henderson TCGv_i64 addr; 233498a9cb79SRichard Henderson 233598a9cb79SRichard Henderson nullify_over(ctx); 233698a9cb79SRichard Henderson 2337deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2338deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2339eed14219SRichard Henderson 2340deee69a1SRichard Henderson if (a->imm) { 2341e5d487c9SRichard Henderson level = tcg_constant_i32(a->ri & 3); 234298a9cb79SRichard Henderson } else { 2343eed14219SRichard Henderson level = tcg_temp_new_i32(); 23446fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(level, load_gpr(ctx, a->ri)); 2345eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 234698a9cb79SRichard Henderson } 234729dd6f64SRichard Henderson want = tcg_constant_i32(a->write ? PAGE_WRITE : PAGE_READ); 2348eed14219SRichard Henderson 2349ad75a51eSRichard Henderson gen_helper_probe(dest, tcg_env, addr, level, want); 2350eed14219SRichard Henderson 2351deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 235231234768SRichard Henderson return nullify_end(ctx); 235398a9cb79SRichard Henderson } 235498a9cb79SRichard Henderson 2355deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 23568d6ae7fbSRichard Henderson { 23578577f354SRichard Henderson if (ctx->is_pa20) { 23588577f354SRichard Henderson return false; 23598577f354SRichard Henderson } 2360deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2361deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23626fd0c7bcSRichard Henderson TCGv_i64 addr; 23636fd0c7bcSRichard Henderson TCGv_i64 ofs, reg; 23648d6ae7fbSRichard Henderson 23658d6ae7fbSRichard Henderson nullify_over(ctx); 23668d6ae7fbSRichard Henderson 2367deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2368deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2369deee69a1SRichard Henderson if (a->addr) { 23708577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 23718d6ae7fbSRichard Henderson } else { 23728577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 23738d6ae7fbSRichard Henderson } 23748d6ae7fbSRichard Henderson 237532dc7569SSven Schnelle /* Exit TB for TLB change if mmu is enabled. */ 237632dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 237731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 237831234768SRichard Henderson } 237931234768SRichard Henderson return nullify_end(ctx); 2380deee69a1SRichard Henderson #endif 23818d6ae7fbSRichard Henderson } 238263300a00SRichard Henderson 2383eb25d10fSHelge Deller static bool do_pxtlb(DisasContext *ctx, arg_ldst *a, bool local) 238463300a00SRichard Henderson { 2385deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2386deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 23876fd0c7bcSRichard Henderson TCGv_i64 addr; 23886fd0c7bcSRichard Henderson TCGv_i64 ofs; 238963300a00SRichard Henderson 239063300a00SRichard Henderson nullify_over(ctx); 239163300a00SRichard Henderson 2392deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2393eb25d10fSHelge Deller 2394eb25d10fSHelge Deller /* 2395eb25d10fSHelge Deller * Page align now, rather than later, so that we can add in the 2396eb25d10fSHelge Deller * page_size field from pa2.0 from the low 4 bits of GR[b]. 2397eb25d10fSHelge Deller */ 2398eb25d10fSHelge Deller tcg_gen_andi_i64(addr, addr, TARGET_PAGE_MASK); 2399eb25d10fSHelge Deller if (ctx->is_pa20) { 2400eb25d10fSHelge Deller tcg_gen_deposit_i64(addr, addr, load_gpr(ctx, a->b), 0, 4); 240163300a00SRichard Henderson } 2402eb25d10fSHelge Deller 2403eb25d10fSHelge Deller if (local) { 2404eb25d10fSHelge Deller gen_helper_ptlb_l(tcg_env, addr); 240563300a00SRichard Henderson } else { 2406ad75a51eSRichard Henderson gen_helper_ptlb(tcg_env, addr); 240763300a00SRichard Henderson } 240863300a00SRichard Henderson 2409eb25d10fSHelge Deller if (a->m) { 2410eb25d10fSHelge Deller save_gpr(ctx, a->b, ofs); 2411eb25d10fSHelge Deller } 2412eb25d10fSHelge Deller 2413eb25d10fSHelge Deller /* Exit TB for TLB change if mmu is enabled. */ 2414eb25d10fSHelge Deller if (ctx->tb_flags & PSW_C) { 2415eb25d10fSHelge Deller ctx->base.is_jmp = DISAS_IAQ_N_STALE; 2416eb25d10fSHelge Deller } 2417eb25d10fSHelge Deller return nullify_end(ctx); 2418eb25d10fSHelge Deller #endif 2419eb25d10fSHelge Deller } 2420eb25d10fSHelge Deller 2421eb25d10fSHelge Deller static bool trans_pxtlb(DisasContext *ctx, arg_ldst *a) 2422eb25d10fSHelge Deller { 2423eb25d10fSHelge Deller return do_pxtlb(ctx, a, false); 2424eb25d10fSHelge Deller } 2425eb25d10fSHelge Deller 2426eb25d10fSHelge Deller static bool trans_pxtlb_l(DisasContext *ctx, arg_ldst *a) 2427eb25d10fSHelge Deller { 2428eb25d10fSHelge Deller return ctx->is_pa20 && do_pxtlb(ctx, a, true); 2429eb25d10fSHelge Deller } 2430eb25d10fSHelge Deller 2431eb25d10fSHelge Deller static bool trans_pxtlbe(DisasContext *ctx, arg_ldst *a) 2432eb25d10fSHelge Deller { 2433eb25d10fSHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2434eb25d10fSHelge Deller #ifndef CONFIG_USER_ONLY 2435eb25d10fSHelge Deller nullify_over(ctx); 2436eb25d10fSHelge Deller 2437eb25d10fSHelge Deller trans_nop_addrx(ctx, a); 2438eb25d10fSHelge Deller gen_helper_ptlbe(tcg_env); 2439eb25d10fSHelge Deller 244063300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 244132dc7569SSven Schnelle if (ctx->tb_flags & PSW_C) { 244231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 244331234768SRichard Henderson } 244431234768SRichard Henderson return nullify_end(ctx); 2445deee69a1SRichard Henderson #endif 244663300a00SRichard Henderson } 24472dfcca9fSRichard Henderson 24486797c315SNick Hudson /* 24496797c315SNick Hudson * Implement the pcxl and pcxl2 Fast TLB Insert instructions. 24506797c315SNick Hudson * See 24516797c315SNick Hudson * https://parisc.wiki.kernel.org/images-parisc/a/a9/Pcxl2_ers.pdf 24526797c315SNick Hudson * page 13-9 (195/206) 24536797c315SNick Hudson */ 24546797c315SNick Hudson static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a) 24556797c315SNick Hudson { 24568577f354SRichard Henderson if (ctx->is_pa20) { 24578577f354SRichard Henderson return false; 24588577f354SRichard Henderson } 24596797c315SNick Hudson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 24606797c315SNick Hudson #ifndef CONFIG_USER_ONLY 24616fd0c7bcSRichard Henderson TCGv_i64 addr, atl, stl; 24626fd0c7bcSRichard Henderson TCGv_i64 reg; 24636797c315SNick Hudson 24646797c315SNick Hudson nullify_over(ctx); 24656797c315SNick Hudson 24666797c315SNick Hudson /* 24676797c315SNick Hudson * FIXME: 24686797c315SNick Hudson * if (not (pcxl or pcxl2)) 24696797c315SNick Hudson * return gen_illegal(ctx); 24706797c315SNick Hudson */ 24716797c315SNick Hudson 24726fd0c7bcSRichard Henderson atl = tcg_temp_new_i64(); 24736fd0c7bcSRichard Henderson stl = tcg_temp_new_i64(); 24746fd0c7bcSRichard Henderson addr = tcg_temp_new_i64(); 24756797c315SNick Hudson 2476ad75a51eSRichard Henderson tcg_gen_ld32u_i64(stl, tcg_env, 24776797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_ISR]) 24786797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIASQ])); 2479ad75a51eSRichard Henderson tcg_gen_ld32u_i64(atl, tcg_env, 24806797c315SNick Hudson a->data ? offsetof(CPUHPPAState, cr[CR_IOR]) 24816797c315SNick Hudson : offsetof(CPUHPPAState, cr[CR_IIAOQ])); 24826797c315SNick Hudson tcg_gen_shli_i64(stl, stl, 32); 2483d265360fSRichard Henderson tcg_gen_or_i64(addr, atl, stl); 24846797c315SNick Hudson 24856797c315SNick Hudson reg = load_gpr(ctx, a->r); 24866797c315SNick Hudson if (a->addr) { 24878577f354SRichard Henderson gen_helper_itlba_pa11(tcg_env, addr, reg); 24886797c315SNick Hudson } else { 24898577f354SRichard Henderson gen_helper_itlbp_pa11(tcg_env, addr, reg); 24906797c315SNick Hudson } 24916797c315SNick Hudson 24926797c315SNick Hudson /* Exit TB for TLB change if mmu is enabled. */ 24936797c315SNick Hudson if (ctx->tb_flags & PSW_C) { 24946797c315SNick Hudson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 24956797c315SNick Hudson } 24966797c315SNick Hudson return nullify_end(ctx); 24976797c315SNick Hudson #endif 24986797c315SNick Hudson } 24996797c315SNick Hudson 25008577f354SRichard Henderson static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a) 25018577f354SRichard Henderson { 25028577f354SRichard Henderson if (!ctx->is_pa20) { 25038577f354SRichard Henderson return false; 25048577f354SRichard Henderson } 25058577f354SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 25068577f354SRichard Henderson #ifndef CONFIG_USER_ONLY 25078577f354SRichard Henderson nullify_over(ctx); 25088577f354SRichard Henderson { 25098577f354SRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 25108577f354SRichard Henderson TCGv_i64 src2 = load_gpr(ctx, a->r2); 25118577f354SRichard Henderson 25128577f354SRichard Henderson if (a->data) { 25138577f354SRichard Henderson gen_helper_idtlbt_pa20(tcg_env, src1, src2); 25148577f354SRichard Henderson } else { 25158577f354SRichard Henderson gen_helper_iitlbt_pa20(tcg_env, src1, src2); 25168577f354SRichard Henderson } 25178577f354SRichard Henderson } 25188577f354SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 25198577f354SRichard Henderson if (ctx->tb_flags & PSW_C) { 25208577f354SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 25218577f354SRichard Henderson } 25228577f354SRichard Henderson return nullify_end(ctx); 25238577f354SRichard Henderson #endif 25248577f354SRichard Henderson } 25258577f354SRichard Henderson 2526deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 25272dfcca9fSRichard Henderson { 2528deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2529deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 25306fd0c7bcSRichard Henderson TCGv_i64 vaddr; 25316fd0c7bcSRichard Henderson TCGv_i64 ofs, paddr; 25322dfcca9fSRichard Henderson 25332dfcca9fSRichard Henderson nullify_over(ctx); 25342dfcca9fSRichard Henderson 2535deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 25362dfcca9fSRichard Henderson 2537aac0f603SRichard Henderson paddr = tcg_temp_new_i64(); 2538ad75a51eSRichard Henderson gen_helper_lpa(paddr, tcg_env, vaddr); 25392dfcca9fSRichard Henderson 25402dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2541deee69a1SRichard Henderson if (a->m) { 2542deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 25432dfcca9fSRichard Henderson } 2544deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 25452dfcca9fSRichard Henderson 254631234768SRichard Henderson return nullify_end(ctx); 2547deee69a1SRichard Henderson #endif 25482dfcca9fSRichard Henderson } 254943a97b81SRichard Henderson 2550deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 255143a97b81SRichard Henderson { 255243a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 255343a97b81SRichard Henderson 255443a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 255543a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 255643a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 255743a97b81SRichard Henderson since the entire address space is coherent. */ 2558a4db4a78SRichard Henderson save_gpr(ctx, a->t, ctx->zero); 255943a97b81SRichard Henderson 256031234768SRichard Henderson cond_free(&ctx->null_cond); 256131234768SRichard Henderson return true; 256243a97b81SRichard Henderson } 256398a9cb79SRichard Henderson 2564faf97ba1SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2565b2167459SRichard Henderson { 25660c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2567b2167459SRichard Henderson } 2568b2167459SRichard Henderson 2569faf97ba1SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2570b2167459SRichard Henderson { 25710c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2572b2167459SRichard Henderson } 2573b2167459SRichard Henderson 2574faf97ba1SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2575b2167459SRichard Henderson { 25760c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2577b2167459SRichard Henderson } 2578b2167459SRichard Henderson 2579faf97ba1SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_d_sh *a) 2580b2167459SRichard Henderson { 25810c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 25820c982a28SRichard Henderson } 2583b2167459SRichard Henderson 2584faf97ba1SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_d_sh *a) 25850c982a28SRichard Henderson { 25860c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 25870c982a28SRichard Henderson } 25880c982a28SRichard Henderson 258963c427c6SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf_d *a) 25900c982a28SRichard Henderson { 25910c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 25920c982a28SRichard Henderson } 25930c982a28SRichard Henderson 259463c427c6SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 25950c982a28SRichard Henderson { 25960c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 25970c982a28SRichard Henderson } 25980c982a28SRichard Henderson 259963c427c6SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf_d *a) 26000c982a28SRichard Henderson { 26010c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 26020c982a28SRichard Henderson } 26030c982a28SRichard Henderson 260463c427c6SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf_d *a) 26050c982a28SRichard Henderson { 26060c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 26070c982a28SRichard Henderson } 26080c982a28SRichard Henderson 260963c427c6SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf_d *a) 26100c982a28SRichard Henderson { 26110c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 26120c982a28SRichard Henderson } 26130c982a28SRichard Henderson 261463c427c6SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf_d *a) 26150c982a28SRichard Henderson { 26160c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 26170c982a28SRichard Henderson } 26180c982a28SRichard Henderson 2619fa8e3bedSRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf_d *a) 26200c982a28SRichard Henderson { 26216fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_i64); 26220c982a28SRichard Henderson } 26230c982a28SRichard Henderson 2624fa8e3bedSRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf_d *a) 26250c982a28SRichard Henderson { 26266fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_i64); 26270c982a28SRichard Henderson } 26280c982a28SRichard Henderson 2629fa8e3bedSRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf_d *a) 26300c982a28SRichard Henderson { 26310c982a28SRichard Henderson if (a->cf == 0) { 26320c982a28SRichard Henderson unsigned r2 = a->r2; 26330c982a28SRichard Henderson unsigned r1 = a->r1; 26340c982a28SRichard Henderson unsigned rt = a->t; 26350c982a28SRichard Henderson 26367aee8189SRichard Henderson if (rt == 0) { /* NOP */ 26377aee8189SRichard Henderson cond_free(&ctx->null_cond); 26387aee8189SRichard Henderson return true; 26397aee8189SRichard Henderson } 26407aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2641b2167459SRichard Henderson if (r1 == 0) { 26426fd0c7bcSRichard Henderson TCGv_i64 dest = dest_gpr(ctx, rt); 26436fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 2644b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2645b2167459SRichard Henderson } else { 2646b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2647b2167459SRichard Henderson } 2648b2167459SRichard Henderson cond_free(&ctx->null_cond); 264931234768SRichard Henderson return true; 2650b2167459SRichard Henderson } 26517aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 26527aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 26537aee8189SRichard Henderson * 26547aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 26557aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 26567aee8189SRichard Henderson * currently implemented as idle. 26577aee8189SRichard Henderson */ 26587aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 26597aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 26607aee8189SRichard Henderson until the next timer interrupt. */ 26617aee8189SRichard Henderson nullify_over(ctx); 26627aee8189SRichard Henderson 26637aee8189SRichard Henderson /* Advance the instruction queue. */ 2664741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 2665741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 26667aee8189SRichard Henderson nullify_set(ctx, 0); 26677aee8189SRichard Henderson 26687aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 2669ad75a51eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), tcg_env, 267029dd6f64SRichard Henderson offsetof(CPUState, halted) - offsetof(HPPACPU, env)); 26717aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 26727aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 26737aee8189SRichard Henderson 26747aee8189SRichard Henderson return nullify_end(ctx); 26757aee8189SRichard Henderson } 26767aee8189SRichard Henderson #endif 26777aee8189SRichard Henderson } 26786fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_i64); 26797aee8189SRichard Henderson } 2680b2167459SRichard Henderson 2681fa8e3bedSRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf_d *a) 2682b2167459SRichard Henderson { 26836fd0c7bcSRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_i64); 26840c982a28SRichard Henderson } 26850c982a28SRichard Henderson 2686345aa35fSRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf_d *a) 26870c982a28SRichard Henderson { 26886fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2689b2167459SRichard Henderson 26900c982a28SRichard Henderson if (a->cf) { 2691b2167459SRichard Henderson nullify_over(ctx); 2692b2167459SRichard Henderson } 26930c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26940c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2695345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d); 269631234768SRichard Henderson return nullify_end(ctx); 2697b2167459SRichard Henderson } 2698b2167459SRichard Henderson 2699af240753SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf_d *a) 2700b2167459SRichard Henderson { 27016fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2; 2702b2167459SRichard Henderson 27030c982a28SRichard Henderson if (a->cf) { 2704b2167459SRichard Henderson nullify_over(ctx); 2705b2167459SRichard Henderson } 27060c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 27070c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 27086fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, a->d, false, tcg_gen_xor_i64); 270931234768SRichard Henderson return nullify_end(ctx); 2710b2167459SRichard Henderson } 2711b2167459SRichard Henderson 2712af240753SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a, bool is_tc) 2713b2167459SRichard Henderson { 27146fd0c7bcSRichard Henderson TCGv_i64 tcg_r1, tcg_r2, tmp; 2715b2167459SRichard Henderson 27160c982a28SRichard Henderson if (a->cf) { 2717b2167459SRichard Henderson nullify_over(ctx); 2718b2167459SRichard Henderson } 27190c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 27200c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2721aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 27226fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tcg_r2); 27236fd0c7bcSRichard Henderson do_unit(ctx, a->t, tcg_r1, tmp, a->cf, a->d, is_tc, tcg_gen_add_i64); 272431234768SRichard Henderson return nullify_end(ctx); 2725b2167459SRichard Henderson } 2726b2167459SRichard Henderson 2727af240753SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf_d *a) 2728b2167459SRichard Henderson { 27290c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 27300c982a28SRichard Henderson } 27310c982a28SRichard Henderson 2732af240753SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf_d *a) 27330c982a28SRichard Henderson { 27340c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 27350c982a28SRichard Henderson } 27360c982a28SRichard Henderson 2737af240753SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf_d *a, bool is_i) 27380c982a28SRichard Henderson { 27396fd0c7bcSRichard Henderson TCGv_i64 tmp; 2740b2167459SRichard Henderson 2741b2167459SRichard Henderson nullify_over(ctx); 2742b2167459SRichard Henderson 2743aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 27446fd0c7bcSRichard Henderson tcg_gen_shri_i64(tmp, cpu_psw_cb, 3); 2745b2167459SRichard Henderson if (!is_i) { 27466fd0c7bcSRichard Henderson tcg_gen_not_i64(tmp, tmp); 2747b2167459SRichard Henderson } 27486fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, (uint64_t)0x1111111111111111ull); 27496fd0c7bcSRichard Henderson tcg_gen_muli_i64(tmp, tmp, 6); 2750af240753SRichard Henderson do_unit(ctx, a->t, load_gpr(ctx, a->r), tmp, a->cf, a->d, false, 27516fd0c7bcSRichard Henderson is_i ? tcg_gen_add_i64 : tcg_gen_sub_i64); 275231234768SRichard Henderson return nullify_end(ctx); 2753b2167459SRichard Henderson } 2754b2167459SRichard Henderson 2755af240753SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf_d *a) 2756b2167459SRichard Henderson { 27570c982a28SRichard Henderson return do_dcor(ctx, a, false); 27580c982a28SRichard Henderson } 27590c982a28SRichard Henderson 2760af240753SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf_d *a) 27610c982a28SRichard Henderson { 27620c982a28SRichard Henderson return do_dcor(ctx, a, true); 27630c982a28SRichard Henderson } 27640c982a28SRichard Henderson 27650c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 27660c982a28SRichard Henderson { 2767a4db4a78SRichard Henderson TCGv_i64 dest, add1, add2, addc, in1, in2; 27686fd0c7bcSRichard Henderson TCGv_i64 cout; 2769b2167459SRichard Henderson 2770b2167459SRichard Henderson nullify_over(ctx); 2771b2167459SRichard Henderson 27720c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 27730c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2774b2167459SRichard Henderson 2775aac0f603SRichard Henderson add1 = tcg_temp_new_i64(); 2776aac0f603SRichard Henderson add2 = tcg_temp_new_i64(); 2777aac0f603SRichard Henderson addc = tcg_temp_new_i64(); 2778aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 2779b2167459SRichard Henderson 2780b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 27816fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, in1, in1); 27826fd0c7bcSRichard Henderson tcg_gen_add_i64(add1, add1, get_psw_carry(ctx, false)); 2783b2167459SRichard Henderson 278472ca8753SRichard Henderson /* 278572ca8753SRichard Henderson * Add or subtract R2, depending on PSW[V]. Proper computation of 278672ca8753SRichard Henderson * carry requires that we subtract via + ~R2 + 1, as described in 278772ca8753SRichard Henderson * the manual. By extracting and masking V, we can produce the 278872ca8753SRichard Henderson * proper inputs to the addition without movcond. 278972ca8753SRichard Henderson */ 27906fd0c7bcSRichard Henderson tcg_gen_sextract_i64(addc, cpu_psw_v, 31, 1); 27916fd0c7bcSRichard Henderson tcg_gen_xor_i64(add2, in2, addc); 27926fd0c7bcSRichard Henderson tcg_gen_andi_i64(addc, addc, 1); 279372ca8753SRichard Henderson 2794a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); 2795a4db4a78SRichard Henderson tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, 2796a4db4a78SRichard Henderson addc, ctx->zero); 2797b2167459SRichard Henderson 2798b2167459SRichard Henderson /* Write back the result register. */ 27990c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2800b2167459SRichard Henderson 2801b2167459SRichard Henderson /* Write back PSW[CB]. */ 28026fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, add1, add2); 28036fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_cb, cpu_psw_cb, dest); 2804b2167459SRichard Henderson 2805b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 280672ca8753SRichard Henderson cout = get_psw_carry(ctx, false); 28076fd0c7bcSRichard Henderson tcg_gen_neg_i64(cpu_psw_v, cout); 28086fd0c7bcSRichard Henderson tcg_gen_xor_i64(cpu_psw_v, cpu_psw_v, in2); 2809b2167459SRichard Henderson 2810b2167459SRichard Henderson /* Install the new nullification. */ 28110c982a28SRichard Henderson if (a->cf) { 28126fd0c7bcSRichard Henderson TCGv_i64 sv = NULL; 2813b47a4a02SSven Schnelle if (cond_need_sv(a->cf >> 1)) { 2814b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 2815b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 2816b2167459SRichard Henderson } 2817a751eb31SRichard Henderson ctx->null_cond = do_cond(ctx, a->cf, false, dest, cout, sv); 2818b2167459SRichard Henderson } 2819b2167459SRichard Henderson 282031234768SRichard Henderson return nullify_end(ctx); 2821b2167459SRichard Henderson } 2822b2167459SRichard Henderson 28230588e061SRichard Henderson static bool trans_addi(DisasContext *ctx, arg_rri_cf *a) 2824b2167459SRichard Henderson { 28250588e061SRichard Henderson return do_add_imm(ctx, a, false, false); 28260588e061SRichard Henderson } 28270588e061SRichard Henderson 28280588e061SRichard Henderson static bool trans_addi_tsv(DisasContext *ctx, arg_rri_cf *a) 28290588e061SRichard Henderson { 28300588e061SRichard Henderson return do_add_imm(ctx, a, true, false); 28310588e061SRichard Henderson } 28320588e061SRichard Henderson 28330588e061SRichard Henderson static bool trans_addi_tc(DisasContext *ctx, arg_rri_cf *a) 28340588e061SRichard Henderson { 28350588e061SRichard Henderson return do_add_imm(ctx, a, false, true); 28360588e061SRichard Henderson } 28370588e061SRichard Henderson 28380588e061SRichard Henderson static bool trans_addi_tc_tsv(DisasContext *ctx, arg_rri_cf *a) 28390588e061SRichard Henderson { 28400588e061SRichard Henderson return do_add_imm(ctx, a, true, true); 28410588e061SRichard Henderson } 28420588e061SRichard Henderson 28430588e061SRichard Henderson static bool trans_subi(DisasContext *ctx, arg_rri_cf *a) 28440588e061SRichard Henderson { 28450588e061SRichard Henderson return do_sub_imm(ctx, a, false); 28460588e061SRichard Henderson } 28470588e061SRichard Henderson 28480588e061SRichard Henderson static bool trans_subi_tsv(DisasContext *ctx, arg_rri_cf *a) 28490588e061SRichard Henderson { 28500588e061SRichard Henderson return do_sub_imm(ctx, a, true); 28510588e061SRichard Henderson } 28520588e061SRichard Henderson 2853345aa35fSRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, arg_rri_cf_d *a) 28540588e061SRichard Henderson { 28556fd0c7bcSRichard Henderson TCGv_i64 tcg_im, tcg_r2; 2856b2167459SRichard Henderson 28570588e061SRichard Henderson if (a->cf) { 2858b2167459SRichard Henderson nullify_over(ctx); 2859b2167459SRichard Henderson } 2860b2167459SRichard Henderson 28616fd0c7bcSRichard Henderson tcg_im = tcg_constant_i64(a->i); 28620588e061SRichard Henderson tcg_r2 = load_gpr(ctx, a->r); 2863345aa35fSRichard Henderson do_cmpclr(ctx, a->t, tcg_im, tcg_r2, a->cf, a->d); 2864b2167459SRichard Henderson 286531234768SRichard Henderson return nullify_end(ctx); 2866b2167459SRichard Henderson } 2867b2167459SRichard Henderson 28680843563fSRichard Henderson static bool do_multimedia(DisasContext *ctx, arg_rrr *a, 28690843563fSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, TCGv_i64)) 28700843563fSRichard Henderson { 28710843563fSRichard Henderson TCGv_i64 r1, r2, dest; 28720843563fSRichard Henderson 28730843563fSRichard Henderson if (!ctx->is_pa20) { 28740843563fSRichard Henderson return false; 28750843563fSRichard Henderson } 28760843563fSRichard Henderson 28770843563fSRichard Henderson nullify_over(ctx); 28780843563fSRichard Henderson 28790843563fSRichard Henderson r1 = load_gpr(ctx, a->r1); 28800843563fSRichard Henderson r2 = load_gpr(ctx, a->r2); 28810843563fSRichard Henderson dest = dest_gpr(ctx, a->t); 28820843563fSRichard Henderson 28830843563fSRichard Henderson fn(dest, r1, r2); 28840843563fSRichard Henderson save_gpr(ctx, a->t, dest); 28850843563fSRichard Henderson 28860843563fSRichard Henderson return nullify_end(ctx); 28870843563fSRichard Henderson } 28880843563fSRichard Henderson 2889151f309bSRichard Henderson static bool do_multimedia_sh(DisasContext *ctx, arg_rri *a, 2890151f309bSRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, int64_t)) 2891151f309bSRichard Henderson { 2892151f309bSRichard Henderson TCGv_i64 r, dest; 2893151f309bSRichard Henderson 2894151f309bSRichard Henderson if (!ctx->is_pa20) { 2895151f309bSRichard Henderson return false; 2896151f309bSRichard Henderson } 2897151f309bSRichard Henderson 2898151f309bSRichard Henderson nullify_over(ctx); 2899151f309bSRichard Henderson 2900151f309bSRichard Henderson r = load_gpr(ctx, a->r); 2901151f309bSRichard Henderson dest = dest_gpr(ctx, a->t); 2902151f309bSRichard Henderson 2903151f309bSRichard Henderson fn(dest, r, a->i); 2904151f309bSRichard Henderson save_gpr(ctx, a->t, dest); 2905151f309bSRichard Henderson 2906151f309bSRichard Henderson return nullify_end(ctx); 2907151f309bSRichard Henderson } 2908151f309bSRichard Henderson 29093bbb8e48SRichard Henderson static bool do_multimedia_shadd(DisasContext *ctx, arg_rrr_sh *a, 29103bbb8e48SRichard Henderson void (*fn)(TCGv_i64, TCGv_i64, 29113bbb8e48SRichard Henderson TCGv_i64, TCGv_i32)) 29123bbb8e48SRichard Henderson { 29133bbb8e48SRichard Henderson TCGv_i64 r1, r2, dest; 29143bbb8e48SRichard Henderson 29153bbb8e48SRichard Henderson if (!ctx->is_pa20) { 29163bbb8e48SRichard Henderson return false; 29173bbb8e48SRichard Henderson } 29183bbb8e48SRichard Henderson 29193bbb8e48SRichard Henderson nullify_over(ctx); 29203bbb8e48SRichard Henderson 29213bbb8e48SRichard Henderson r1 = load_gpr(ctx, a->r1); 29223bbb8e48SRichard Henderson r2 = load_gpr(ctx, a->r2); 29233bbb8e48SRichard Henderson dest = dest_gpr(ctx, a->t); 29243bbb8e48SRichard Henderson 29253bbb8e48SRichard Henderson fn(dest, r1, r2, tcg_constant_i32(a->sh)); 29263bbb8e48SRichard Henderson save_gpr(ctx, a->t, dest); 29273bbb8e48SRichard Henderson 29283bbb8e48SRichard Henderson return nullify_end(ctx); 29293bbb8e48SRichard Henderson } 29303bbb8e48SRichard Henderson 29310843563fSRichard Henderson static bool trans_hadd(DisasContext *ctx, arg_rrr *a) 29320843563fSRichard Henderson { 29330843563fSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_add16_i64); 29340843563fSRichard Henderson } 29350843563fSRichard Henderson 29360843563fSRichard Henderson static bool trans_hadd_ss(DisasContext *ctx, arg_rrr *a) 29370843563fSRichard Henderson { 29380843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_ss); 29390843563fSRichard Henderson } 29400843563fSRichard Henderson 29410843563fSRichard Henderson static bool trans_hadd_us(DisasContext *ctx, arg_rrr *a) 29420843563fSRichard Henderson { 29430843563fSRichard Henderson return do_multimedia(ctx, a, gen_helper_hadd_us); 29440843563fSRichard Henderson } 29450843563fSRichard Henderson 29461b3cb7c8SRichard Henderson static bool trans_havg(DisasContext *ctx, arg_rrr *a) 29471b3cb7c8SRichard Henderson { 29481b3cb7c8SRichard Henderson return do_multimedia(ctx, a, gen_helper_havg); 29491b3cb7c8SRichard Henderson } 29501b3cb7c8SRichard Henderson 2951151f309bSRichard Henderson static bool trans_hshl(DisasContext *ctx, arg_rri *a) 2952151f309bSRichard Henderson { 2953151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shl16i_i64); 2954151f309bSRichard Henderson } 2955151f309bSRichard Henderson 2956151f309bSRichard Henderson static bool trans_hshr_s(DisasContext *ctx, arg_rri *a) 2957151f309bSRichard Henderson { 2958151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_sar16i_i64); 2959151f309bSRichard Henderson } 2960151f309bSRichard Henderson 2961151f309bSRichard Henderson static bool trans_hshr_u(DisasContext *ctx, arg_rri *a) 2962151f309bSRichard Henderson { 2963151f309bSRichard Henderson return do_multimedia_sh(ctx, a, tcg_gen_vec_shr16i_i64); 2964151f309bSRichard Henderson } 2965151f309bSRichard Henderson 29663bbb8e48SRichard Henderson static bool trans_hshladd(DisasContext *ctx, arg_rrr_sh *a) 29673bbb8e48SRichard Henderson { 29683bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshladd); 29693bbb8e48SRichard Henderson } 29703bbb8e48SRichard Henderson 29713bbb8e48SRichard Henderson static bool trans_hshradd(DisasContext *ctx, arg_rrr_sh *a) 29723bbb8e48SRichard Henderson { 29733bbb8e48SRichard Henderson return do_multimedia_shadd(ctx, a, gen_helper_hshradd); 29743bbb8e48SRichard Henderson } 29753bbb8e48SRichard Henderson 297610c9e58dSRichard Henderson static bool trans_hsub(DisasContext *ctx, arg_rrr *a) 297710c9e58dSRichard Henderson { 297810c9e58dSRichard Henderson return do_multimedia(ctx, a, tcg_gen_vec_sub16_i64); 297910c9e58dSRichard Henderson } 298010c9e58dSRichard Henderson 298110c9e58dSRichard Henderson static bool trans_hsub_ss(DisasContext *ctx, arg_rrr *a) 298210c9e58dSRichard Henderson { 298310c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_ss); 298410c9e58dSRichard Henderson } 298510c9e58dSRichard Henderson 298610c9e58dSRichard Henderson static bool trans_hsub_us(DisasContext *ctx, arg_rrr *a) 298710c9e58dSRichard Henderson { 298810c9e58dSRichard Henderson return do_multimedia(ctx, a, gen_helper_hsub_us); 298910c9e58dSRichard Henderson } 299010c9e58dSRichard Henderson 2991c2a7ee3fSRichard Henderson static void gen_mixh_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 2992c2a7ee3fSRichard Henderson { 2993c2a7ee3fSRichard Henderson uint64_t mask = 0xffff0000ffff0000ull; 2994c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 2995c2a7ee3fSRichard Henderson 2996c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r2, mask); 2997c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r1, mask); 2998c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, tmp, 16); 2999c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3000c2a7ee3fSRichard Henderson } 3001c2a7ee3fSRichard Henderson 3002c2a7ee3fSRichard Henderson static bool trans_mixh_l(DisasContext *ctx, arg_rrr *a) 3003c2a7ee3fSRichard Henderson { 3004c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_l); 3005c2a7ee3fSRichard Henderson } 3006c2a7ee3fSRichard Henderson 3007c2a7ee3fSRichard Henderson static void gen_mixh_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3008c2a7ee3fSRichard Henderson { 3009c2a7ee3fSRichard Henderson uint64_t mask = 0x0000ffff0000ffffull; 3010c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3011c2a7ee3fSRichard Henderson 3012c2a7ee3fSRichard Henderson tcg_gen_andi_i64(tmp, r1, mask); 3013c2a7ee3fSRichard Henderson tcg_gen_andi_i64(dst, r2, mask); 3014c2a7ee3fSRichard Henderson tcg_gen_shli_i64(tmp, tmp, 16); 3015c2a7ee3fSRichard Henderson tcg_gen_or_i64(dst, dst, tmp); 3016c2a7ee3fSRichard Henderson } 3017c2a7ee3fSRichard Henderson 3018c2a7ee3fSRichard Henderson static bool trans_mixh_r(DisasContext *ctx, arg_rrr *a) 3019c2a7ee3fSRichard Henderson { 3020c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixh_r); 3021c2a7ee3fSRichard Henderson } 3022c2a7ee3fSRichard Henderson 3023c2a7ee3fSRichard Henderson static void gen_mixw_l(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3024c2a7ee3fSRichard Henderson { 3025c2a7ee3fSRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3026c2a7ee3fSRichard Henderson 3027c2a7ee3fSRichard Henderson tcg_gen_shri_i64(tmp, r2, 32); 3028c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r1, tmp, 0, 32); 3029c2a7ee3fSRichard Henderson } 3030c2a7ee3fSRichard Henderson 3031c2a7ee3fSRichard Henderson static bool trans_mixw_l(DisasContext *ctx, arg_rrr *a) 3032c2a7ee3fSRichard Henderson { 3033c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_l); 3034c2a7ee3fSRichard Henderson } 3035c2a7ee3fSRichard Henderson 3036c2a7ee3fSRichard Henderson static void gen_mixw_r(TCGv_i64 dst, TCGv_i64 r1, TCGv_i64 r2) 3037c2a7ee3fSRichard Henderson { 3038c2a7ee3fSRichard Henderson tcg_gen_deposit_i64(dst, r2, r1, 32, 32); 3039c2a7ee3fSRichard Henderson } 3040c2a7ee3fSRichard Henderson 3041c2a7ee3fSRichard Henderson static bool trans_mixw_r(DisasContext *ctx, arg_rrr *a) 3042c2a7ee3fSRichard Henderson { 3043c2a7ee3fSRichard Henderson return do_multimedia(ctx, a, gen_mixw_r); 3044c2a7ee3fSRichard Henderson } 3045c2a7ee3fSRichard Henderson 30464e7abdb1SRichard Henderson static bool trans_permh(DisasContext *ctx, arg_permh *a) 30474e7abdb1SRichard Henderson { 30484e7abdb1SRichard Henderson TCGv_i64 r, t0, t1, t2, t3; 30494e7abdb1SRichard Henderson 30504e7abdb1SRichard Henderson if (!ctx->is_pa20) { 30514e7abdb1SRichard Henderson return false; 30524e7abdb1SRichard Henderson } 30534e7abdb1SRichard Henderson 30544e7abdb1SRichard Henderson nullify_over(ctx); 30554e7abdb1SRichard Henderson 30564e7abdb1SRichard Henderson r = load_gpr(ctx, a->r1); 30574e7abdb1SRichard Henderson t0 = tcg_temp_new_i64(); 30584e7abdb1SRichard Henderson t1 = tcg_temp_new_i64(); 30594e7abdb1SRichard Henderson t2 = tcg_temp_new_i64(); 30604e7abdb1SRichard Henderson t3 = tcg_temp_new_i64(); 30614e7abdb1SRichard Henderson 30624e7abdb1SRichard Henderson tcg_gen_extract_i64(t0, r, (3 - a->c0) * 16, 16); 30634e7abdb1SRichard Henderson tcg_gen_extract_i64(t1, r, (3 - a->c1) * 16, 16); 30644e7abdb1SRichard Henderson tcg_gen_extract_i64(t2, r, (3 - a->c2) * 16, 16); 30654e7abdb1SRichard Henderson tcg_gen_extract_i64(t3, r, (3 - a->c3) * 16, 16); 30664e7abdb1SRichard Henderson 30674e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t1, t0, 16, 48); 30684e7abdb1SRichard Henderson tcg_gen_deposit_i64(t2, t3, t2, 16, 48); 30694e7abdb1SRichard Henderson tcg_gen_deposit_i64(t0, t2, t0, 32, 32); 30704e7abdb1SRichard Henderson 30714e7abdb1SRichard Henderson save_gpr(ctx, a->t, t0); 30724e7abdb1SRichard Henderson return nullify_end(ctx); 30734e7abdb1SRichard Henderson } 30744e7abdb1SRichard Henderson 30751cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 307696d6407fSRichard Henderson { 3077b5caa17cSRichard Henderson if (ctx->is_pa20) { 3078b5caa17cSRichard Henderson /* 3079b5caa17cSRichard Henderson * With pa20, LDB, LDH, LDW, LDD to %g0 are prefetches. 3080b5caa17cSRichard Henderson * Any base modification still occurs. 3081b5caa17cSRichard Henderson */ 3082b5caa17cSRichard Henderson if (a->t == 0) { 3083b5caa17cSRichard Henderson return trans_nop_addrx(ctx, a); 3084b5caa17cSRichard Henderson } 3085b5caa17cSRichard Henderson } else if (a->size > MO_32) { 30860786a3b6SHelge Deller return gen_illegal(ctx); 3087c53e401eSRichard Henderson } 30881cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 30891cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 309096d6407fSRichard Henderson } 309196d6407fSRichard Henderson 30921cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 309396d6407fSRichard Henderson { 30941cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 3095c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 30960786a3b6SHelge Deller return gen_illegal(ctx); 309796d6407fSRichard Henderson } 3098c53e401eSRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 30990786a3b6SHelge Deller } 310096d6407fSRichard Henderson 31011cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 310296d6407fSRichard Henderson { 3103b1af755cSRichard Henderson MemOp mop = MO_TE | MO_ALIGN | a->size; 3104a4db4a78SRichard Henderson TCGv_i64 dest, ofs; 31056fd0c7bcSRichard Henderson TCGv_i64 addr; 310696d6407fSRichard Henderson 3107c53e401eSRichard Henderson if (!ctx->is_pa20 && a->size > MO_32) { 310851416c4eSRichard Henderson return gen_illegal(ctx); 310951416c4eSRichard Henderson } 311051416c4eSRichard Henderson 311196d6407fSRichard Henderson nullify_over(ctx); 311296d6407fSRichard Henderson 31131cd012a5SRichard Henderson if (a->m) { 311486f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 311586f8d05fSRichard Henderson we see the result of the load. */ 3116aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 311796d6407fSRichard Henderson } else { 31181cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 311996d6407fSRichard Henderson } 312096d6407fSRichard Henderson 31211cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0, 312217fe594cSRichard Henderson a->disp, a->sp, a->m, MMU_DISABLED(ctx)); 3123b1af755cSRichard Henderson 3124b1af755cSRichard Henderson /* 3125b1af755cSRichard Henderson * For hppa1.1, LDCW is undefined unless aligned mod 16. 3126b1af755cSRichard Henderson * However actual hardware succeeds with aligned mod 4. 3127b1af755cSRichard Henderson * Detect this case and log a GUEST_ERROR. 3128b1af755cSRichard Henderson * 3129b1af755cSRichard Henderson * TODO: HPPA64 relaxes the over-alignment requirement 3130b1af755cSRichard Henderson * with the ,co completer. 3131b1af755cSRichard Henderson */ 3132b1af755cSRichard Henderson gen_helper_ldc_check(addr); 3133b1af755cSRichard Henderson 3134a4db4a78SRichard Henderson tcg_gen_atomic_xchg_i64(dest, addr, ctx->zero, ctx->mmu_idx, mop); 3135b1af755cSRichard Henderson 31361cd012a5SRichard Henderson if (a->m) { 31371cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 313896d6407fSRichard Henderson } 31391cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 314096d6407fSRichard Henderson 314131234768SRichard Henderson return nullify_end(ctx); 314296d6407fSRichard Henderson } 314396d6407fSRichard Henderson 31441cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 314596d6407fSRichard Henderson { 31466fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31476fd0c7bcSRichard Henderson TCGv_i64 addr; 314896d6407fSRichard Henderson 314996d6407fSRichard Henderson nullify_over(ctx); 315096d6407fSRichard Henderson 31511cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 315217fe594cSRichard Henderson MMU_DISABLED(ctx)); 31531cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 31541cd012a5SRichard Henderson if (a->a) { 3155f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3156ad75a51eSRichard Henderson gen_helper_stby_e_parallel(tcg_env, addr, val); 3157f9f46db4SEmilio G. Cota } else { 3158ad75a51eSRichard Henderson gen_helper_stby_e(tcg_env, addr, val); 3159f9f46db4SEmilio G. Cota } 3160f9f46db4SEmilio G. Cota } else { 3161f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 3162ad75a51eSRichard Henderson gen_helper_stby_b_parallel(tcg_env, addr, val); 316396d6407fSRichard Henderson } else { 3164ad75a51eSRichard Henderson gen_helper_stby_b(tcg_env, addr, val); 316596d6407fSRichard Henderson } 3166f9f46db4SEmilio G. Cota } 31671cd012a5SRichard Henderson if (a->m) { 31686fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~3); 31691cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 317096d6407fSRichard Henderson } 317196d6407fSRichard Henderson 317231234768SRichard Henderson return nullify_end(ctx); 317396d6407fSRichard Henderson } 317496d6407fSRichard Henderson 317525460fc5SRichard Henderson static bool trans_stdby(DisasContext *ctx, arg_stby *a) 317625460fc5SRichard Henderson { 31776fd0c7bcSRichard Henderson TCGv_i64 ofs, val; 31786fd0c7bcSRichard Henderson TCGv_i64 addr; 317925460fc5SRichard Henderson 318025460fc5SRichard Henderson if (!ctx->is_pa20) { 318125460fc5SRichard Henderson return false; 318225460fc5SRichard Henderson } 318325460fc5SRichard Henderson nullify_over(ctx); 318425460fc5SRichard Henderson 318525460fc5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 318617fe594cSRichard Henderson MMU_DISABLED(ctx)); 318725460fc5SRichard Henderson val = load_gpr(ctx, a->r); 318825460fc5SRichard Henderson if (a->a) { 318925460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 319025460fc5SRichard Henderson gen_helper_stdby_e_parallel(tcg_env, addr, val); 319125460fc5SRichard Henderson } else { 319225460fc5SRichard Henderson gen_helper_stdby_e(tcg_env, addr, val); 319325460fc5SRichard Henderson } 319425460fc5SRichard Henderson } else { 319525460fc5SRichard Henderson if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 319625460fc5SRichard Henderson gen_helper_stdby_b_parallel(tcg_env, addr, val); 319725460fc5SRichard Henderson } else { 319825460fc5SRichard Henderson gen_helper_stdby_b(tcg_env, addr, val); 319925460fc5SRichard Henderson } 320025460fc5SRichard Henderson } 320125460fc5SRichard Henderson if (a->m) { 32026fd0c7bcSRichard Henderson tcg_gen_andi_i64(ofs, ofs, ~7); 320325460fc5SRichard Henderson save_gpr(ctx, a->b, ofs); 320425460fc5SRichard Henderson } 320525460fc5SRichard Henderson 320625460fc5SRichard Henderson return nullify_end(ctx); 320725460fc5SRichard Henderson } 320825460fc5SRichard Henderson 32091cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 3210d0a851ccSRichard Henderson { 3211d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3212d0a851ccSRichard Henderson 3213d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3214451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 32151cd012a5SRichard Henderson trans_ld(ctx, a); 3216d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 321731234768SRichard Henderson return true; 3218d0a851ccSRichard Henderson } 3219d0a851ccSRichard Henderson 32201cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 3221d0a851ccSRichard Henderson { 3222d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 3223d0a851ccSRichard Henderson 3224d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 3225451d993dSRichard Henderson ctx->mmu_idx = ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; 32261cd012a5SRichard Henderson trans_st(ctx, a); 3227d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 322831234768SRichard Henderson return true; 3229d0a851ccSRichard Henderson } 323095412a61SRichard Henderson 32310588e061SRichard Henderson static bool trans_ldil(DisasContext *ctx, arg_ldil *a) 3232b2167459SRichard Henderson { 32336fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3234b2167459SRichard Henderson 32356fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 32360588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3237b2167459SRichard Henderson cond_free(&ctx->null_cond); 323831234768SRichard Henderson return true; 3239b2167459SRichard Henderson } 3240b2167459SRichard Henderson 32410588e061SRichard Henderson static bool trans_addil(DisasContext *ctx, arg_addil *a) 3242b2167459SRichard Henderson { 32436fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = load_gpr(ctx, a->r); 32446fd0c7bcSRichard Henderson TCGv_i64 tcg_r1 = dest_gpr(ctx, 1); 3245b2167459SRichard Henderson 32466fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_r1, tcg_rt, a->i); 3247b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 3248b2167459SRichard Henderson cond_free(&ctx->null_cond); 324931234768SRichard Henderson return true; 3250b2167459SRichard Henderson } 3251b2167459SRichard Henderson 32520588e061SRichard Henderson static bool trans_ldo(DisasContext *ctx, arg_ldo *a) 3253b2167459SRichard Henderson { 32546fd0c7bcSRichard Henderson TCGv_i64 tcg_rt = dest_gpr(ctx, a->t); 3255b2167459SRichard Henderson 3256b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 3257d265360fSRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_i64. */ 32580588e061SRichard Henderson if (a->b == 0) { 32596fd0c7bcSRichard Henderson tcg_gen_movi_i64(tcg_rt, a->i); 3260b2167459SRichard Henderson } else { 32616fd0c7bcSRichard Henderson tcg_gen_addi_i64(tcg_rt, cpu_gr[a->b], a->i); 3262b2167459SRichard Henderson } 32630588e061SRichard Henderson save_gpr(ctx, a->t, tcg_rt); 3264b2167459SRichard Henderson cond_free(&ctx->null_cond); 326531234768SRichard Henderson return true; 3266b2167459SRichard Henderson } 3267b2167459SRichard Henderson 32686fd0c7bcSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 3269e9efd4bcSRichard Henderson unsigned c, unsigned f, bool d, unsigned n, int disp) 327098cd9ca7SRichard Henderson { 32716fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv; 327298cd9ca7SRichard Henderson DisasCond cond; 327398cd9ca7SRichard Henderson 327498cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3275aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 327698cd9ca7SRichard Henderson 32776fd0c7bcSRichard Henderson tcg_gen_sub_i64(dest, in1, in2); 327898cd9ca7SRichard Henderson 3279f764718dSRichard Henderson sv = NULL; 3280b47a4a02SSven Schnelle if (cond_need_sv(c)) { 328198cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 328298cd9ca7SRichard Henderson } 328398cd9ca7SRichard Henderson 32844fe9533aSRichard Henderson cond = do_sub_cond(ctx, c * 2 + f, d, dest, in1, in2, sv); 328501afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 328698cd9ca7SRichard Henderson } 328798cd9ca7SRichard Henderson 328801afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 328998cd9ca7SRichard Henderson { 3290e9efd4bcSRichard Henderson if (!ctx->is_pa20 && a->d) { 3291e9efd4bcSRichard Henderson return false; 3292e9efd4bcSRichard Henderson } 329301afb7beSRichard Henderson nullify_over(ctx); 3294e9efd4bcSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), 3295e9efd4bcSRichard Henderson a->c, a->f, a->d, a->n, a->disp); 329601afb7beSRichard Henderson } 329701afb7beSRichard Henderson 329801afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 329901afb7beSRichard Henderson { 3300c65c3ee1SRichard Henderson if (!ctx->is_pa20 && a->d) { 3301c65c3ee1SRichard Henderson return false; 3302c65c3ee1SRichard Henderson } 330301afb7beSRichard Henderson nullify_over(ctx); 33046fd0c7bcSRichard Henderson return do_cmpb(ctx, a->r, tcg_constant_i64(a->i), 3305c65c3ee1SRichard Henderson a->c, a->f, a->d, a->n, a->disp); 330601afb7beSRichard Henderson } 330701afb7beSRichard Henderson 33086fd0c7bcSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, 330901afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 331001afb7beSRichard Henderson { 33116fd0c7bcSRichard Henderson TCGv_i64 dest, in2, sv, cb_cond; 331298cd9ca7SRichard Henderson DisasCond cond; 3313bdcccc17SRichard Henderson bool d = false; 331498cd9ca7SRichard Henderson 3315f25d3160SRichard Henderson /* 3316f25d3160SRichard Henderson * For hppa64, the ADDB conditions change with PSW.W, 3317f25d3160SRichard Henderson * dropping ZNV, SV, OD in favor of double-word EQ, LT, LE. 3318f25d3160SRichard Henderson */ 3319f25d3160SRichard Henderson if (ctx->tb_flags & PSW_W) { 3320f25d3160SRichard Henderson d = c >= 5; 3321f25d3160SRichard Henderson if (d) { 3322f25d3160SRichard Henderson c &= 3; 3323f25d3160SRichard Henderson } 3324f25d3160SRichard Henderson } 3325f25d3160SRichard Henderson 332698cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 3327aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 3328f764718dSRichard Henderson sv = NULL; 3329bdcccc17SRichard Henderson cb_cond = NULL; 333098cd9ca7SRichard Henderson 3331b47a4a02SSven Schnelle if (cond_need_cb(c)) { 3332aac0f603SRichard Henderson TCGv_i64 cb = tcg_temp_new_i64(); 3333aac0f603SRichard Henderson TCGv_i64 cb_msb = tcg_temp_new_i64(); 3334bdcccc17SRichard Henderson 33356fd0c7bcSRichard Henderson tcg_gen_movi_i64(cb_msb, 0); 33366fd0c7bcSRichard Henderson tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); 33376fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, in1, in2); 33386fd0c7bcSRichard Henderson tcg_gen_xor_i64(cb, cb, dest); 3339bdcccc17SRichard Henderson cb_cond = get_carry(ctx, d, cb, cb_msb); 3340b47a4a02SSven Schnelle } else { 33416fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, in1, in2); 3342b47a4a02SSven Schnelle } 3343b47a4a02SSven Schnelle if (cond_need_sv(c)) { 334498cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 334598cd9ca7SRichard Henderson } 334698cd9ca7SRichard Henderson 3347a751eb31SRichard Henderson cond = do_cond(ctx, c * 2 + f, d, dest, cb_cond, sv); 334843675d20SSven Schnelle save_gpr(ctx, r, dest); 334901afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 335098cd9ca7SRichard Henderson } 335198cd9ca7SRichard Henderson 335201afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 335398cd9ca7SRichard Henderson { 335401afb7beSRichard Henderson nullify_over(ctx); 335501afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 335601afb7beSRichard Henderson } 335701afb7beSRichard Henderson 335801afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 335901afb7beSRichard Henderson { 336001afb7beSRichard Henderson nullify_over(ctx); 33616fd0c7bcSRichard Henderson return do_addb(ctx, a->r, tcg_constant_i64(a->i), a->c, a->f, a->n, a->disp); 336201afb7beSRichard Henderson } 336301afb7beSRichard Henderson 336401afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 336501afb7beSRichard Henderson { 33666fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 336798cd9ca7SRichard Henderson DisasCond cond; 336898cd9ca7SRichard Henderson 336998cd9ca7SRichard Henderson nullify_over(ctx); 337098cd9ca7SRichard Henderson 3371aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 337201afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 337384e224d4SRichard Henderson if (cond_need_ext(ctx, a->d)) { 33741e9ab9fbSRichard Henderson /* Force shift into [32,63] */ 33756fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, cpu_sar, 32); 33766fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, tmp); 33771e9ab9fbSRichard Henderson } else { 33786fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tcg_r, cpu_sar); 33791e9ab9fbSRichard Henderson } 338098cd9ca7SRichard Henderson 33811e9ab9fbSRichard Henderson cond = cond_make_0_tmp(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 338201afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 338398cd9ca7SRichard Henderson } 338498cd9ca7SRichard Henderson 338501afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 338698cd9ca7SRichard Henderson { 33876fd0c7bcSRichard Henderson TCGv_i64 tmp, tcg_r; 338801afb7beSRichard Henderson DisasCond cond; 33891e9ab9fbSRichard Henderson int p; 339001afb7beSRichard Henderson 339101afb7beSRichard Henderson nullify_over(ctx); 339201afb7beSRichard Henderson 3393aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 339401afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 339584e224d4SRichard Henderson p = a->p | (cond_need_ext(ctx, a->d) ? 32 : 0); 33966fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, tcg_r, p); 339701afb7beSRichard Henderson 339801afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 339901afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 340001afb7beSRichard Henderson } 340101afb7beSRichard Henderson 340201afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 340301afb7beSRichard Henderson { 34046fd0c7bcSRichard Henderson TCGv_i64 dest; 340598cd9ca7SRichard Henderson DisasCond cond; 340698cd9ca7SRichard Henderson 340798cd9ca7SRichard Henderson nullify_over(ctx); 340898cd9ca7SRichard Henderson 340901afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 341001afb7beSRichard Henderson if (a->r1 == 0) { 34116fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, 0); 341298cd9ca7SRichard Henderson } else { 34136fd0c7bcSRichard Henderson tcg_gen_mov_i64(dest, cpu_gr[a->r1]); 341498cd9ca7SRichard Henderson } 341598cd9ca7SRichard Henderson 34164fa52edfSRichard Henderson /* All MOVB conditions are 32-bit. */ 34174fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 341801afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 341901afb7beSRichard Henderson } 342001afb7beSRichard Henderson 342101afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 342201afb7beSRichard Henderson { 34236fd0c7bcSRichard Henderson TCGv_i64 dest; 342401afb7beSRichard Henderson DisasCond cond; 342501afb7beSRichard Henderson 342601afb7beSRichard Henderson nullify_over(ctx); 342701afb7beSRichard Henderson 342801afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 34296fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, a->i); 343001afb7beSRichard Henderson 34314fa52edfSRichard Henderson /* All MOVBI conditions are 32-bit. */ 34324fa52edfSRichard Henderson cond = do_sed_cond(ctx, a->c, false, dest); 343301afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 343498cd9ca7SRichard Henderson } 343598cd9ca7SRichard Henderson 3436f7b775a9SRichard Henderson static bool trans_shrp_sar(DisasContext *ctx, arg_shrp_sar *a) 34370b1347d2SRichard Henderson { 34386fd0c7bcSRichard Henderson TCGv_i64 dest, src2; 34390b1347d2SRichard Henderson 3440f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3441f7b775a9SRichard Henderson return false; 3442f7b775a9SRichard Henderson } 344330878590SRichard Henderson if (a->c) { 34440b1347d2SRichard Henderson nullify_over(ctx); 34450b1347d2SRichard Henderson } 34460b1347d2SRichard Henderson 344730878590SRichard Henderson dest = dest_gpr(ctx, a->t); 3448f7b775a9SRichard Henderson src2 = load_gpr(ctx, a->r2); 344930878590SRichard Henderson if (a->r1 == 0) { 3450f7b775a9SRichard Henderson if (a->d) { 34516fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src2, cpu_sar); 3452f7b775a9SRichard Henderson } else { 3453aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 3454f7b775a9SRichard Henderson 34556fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src2); 34566fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, 31); 34576fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, dest, tmp); 3458f7b775a9SRichard Henderson } 345930878590SRichard Henderson } else if (a->r1 == a->r2) { 3460f7b775a9SRichard Henderson if (a->d) { 34616fd0c7bcSRichard Henderson tcg_gen_rotr_i64(dest, src2, cpu_sar); 3462f7b775a9SRichard Henderson } else { 34630b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3464e1d635e8SRichard Henderson TCGv_i32 s32 = tcg_temp_new_i32(); 3465e1d635e8SRichard Henderson 34666fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, src2); 34676fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(s32, cpu_sar); 3468f7b775a9SRichard Henderson tcg_gen_andi_i32(s32, s32, 31); 3469e1d635e8SRichard Henderson tcg_gen_rotr_i32(t32, t32, s32); 34706fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 3471f7b775a9SRichard Henderson } 3472f7b775a9SRichard Henderson } else { 34736fd0c7bcSRichard Henderson TCGv_i64 src1 = load_gpr(ctx, a->r1); 3474f7b775a9SRichard Henderson 3475f7b775a9SRichard Henderson if (a->d) { 3476aac0f603SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 3477aac0f603SRichard Henderson TCGv_i64 n = tcg_temp_new_i64(); 3478f7b775a9SRichard Henderson 34796fd0c7bcSRichard Henderson tcg_gen_xori_i64(n, cpu_sar, 63); 3480a01491a2SHelge Deller tcg_gen_shl_i64(t, src1, n); 34816fd0c7bcSRichard Henderson tcg_gen_shli_i64(t, t, 1); 3482a01491a2SHelge Deller tcg_gen_shr_i64(dest, src2, cpu_sar); 34836fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, t); 34840b1347d2SRichard Henderson } else { 34850b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 34860b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 34870b1347d2SRichard Henderson 34886fd0c7bcSRichard Henderson tcg_gen_concat32_i64(t, src2, src1); 3489967662cdSRichard Henderson tcg_gen_andi_i64(s, cpu_sar, 31); 3490967662cdSRichard Henderson tcg_gen_shr_i64(dest, t, s); 34910b1347d2SRichard Henderson } 3492f7b775a9SRichard Henderson } 349330878590SRichard Henderson save_gpr(ctx, a->t, dest); 34940b1347d2SRichard Henderson 34950b1347d2SRichard Henderson /* Install the new nullification. */ 34960b1347d2SRichard Henderson cond_free(&ctx->null_cond); 349730878590SRichard Henderson if (a->c) { 34984fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 34990b1347d2SRichard Henderson } 350031234768SRichard Henderson return nullify_end(ctx); 35010b1347d2SRichard Henderson } 35020b1347d2SRichard Henderson 3503f7b775a9SRichard Henderson static bool trans_shrp_imm(DisasContext *ctx, arg_shrp_imm *a) 35040b1347d2SRichard Henderson { 3505f7b775a9SRichard Henderson unsigned width, sa; 35066fd0c7bcSRichard Henderson TCGv_i64 dest, t2; 35070b1347d2SRichard Henderson 3508f7b775a9SRichard Henderson if (!ctx->is_pa20 && a->d) { 3509f7b775a9SRichard Henderson return false; 3510f7b775a9SRichard Henderson } 351130878590SRichard Henderson if (a->c) { 35120b1347d2SRichard Henderson nullify_over(ctx); 35130b1347d2SRichard Henderson } 35140b1347d2SRichard Henderson 3515f7b775a9SRichard Henderson width = a->d ? 64 : 32; 3516f7b775a9SRichard Henderson sa = width - 1 - a->cpos; 3517f7b775a9SRichard Henderson 351830878590SRichard Henderson dest = dest_gpr(ctx, a->t); 351930878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 352005bfd4dbSRichard Henderson if (a->r1 == 0) { 35216fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, t2, sa, width - sa); 3522c53e401eSRichard Henderson } else if (width == TARGET_LONG_BITS) { 35236fd0c7bcSRichard Henderson tcg_gen_extract2_i64(dest, t2, cpu_gr[a->r1], sa); 3524f7b775a9SRichard Henderson } else { 3525f7b775a9SRichard Henderson assert(!a->d); 3526f7b775a9SRichard Henderson if (a->r1 == a->r2) { 35270b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 35286fd0c7bcSRichard Henderson tcg_gen_extrl_i64_i32(t32, t2); 35290b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 35306fd0c7bcSRichard Henderson tcg_gen_extu_i32_i64(dest, t32); 35310b1347d2SRichard Henderson } else { 3532967662cdSRichard Henderson tcg_gen_concat32_i64(dest, t2, cpu_gr[a->r1]); 3533967662cdSRichard Henderson tcg_gen_extract_i64(dest, dest, sa, 32); 35340b1347d2SRichard Henderson } 3535f7b775a9SRichard Henderson } 353630878590SRichard Henderson save_gpr(ctx, a->t, dest); 35370b1347d2SRichard Henderson 35380b1347d2SRichard Henderson /* Install the new nullification. */ 35390b1347d2SRichard Henderson cond_free(&ctx->null_cond); 354030878590SRichard Henderson if (a->c) { 35414fa52edfSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, false, dest); 35420b1347d2SRichard Henderson } 354331234768SRichard Henderson return nullify_end(ctx); 35440b1347d2SRichard Henderson } 35450b1347d2SRichard Henderson 3546bd792da3SRichard Henderson static bool trans_extr_sar(DisasContext *ctx, arg_extr_sar *a) 35470b1347d2SRichard Henderson { 3548bd792da3SRichard Henderson unsigned widthm1 = a->d ? 63 : 31; 35496fd0c7bcSRichard Henderson TCGv_i64 dest, src, tmp; 35500b1347d2SRichard Henderson 3551bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3552bd792da3SRichard Henderson return false; 3553bd792da3SRichard Henderson } 355430878590SRichard Henderson if (a->c) { 35550b1347d2SRichard Henderson nullify_over(ctx); 35560b1347d2SRichard Henderson } 35570b1347d2SRichard Henderson 355830878590SRichard Henderson dest = dest_gpr(ctx, a->t); 355930878590SRichard Henderson src = load_gpr(ctx, a->r); 3560aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 35610b1347d2SRichard Henderson 35620b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 35636fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, cpu_sar, widthm1); 35646fd0c7bcSRichard Henderson tcg_gen_xori_i64(tmp, tmp, widthm1); 3565d781cb77SRichard Henderson 356630878590SRichard Henderson if (a->se) { 3567bd792da3SRichard Henderson if (!a->d) { 35686fd0c7bcSRichard Henderson tcg_gen_ext32s_i64(dest, src); 3569bd792da3SRichard Henderson src = dest; 3570bd792da3SRichard Henderson } 35716fd0c7bcSRichard Henderson tcg_gen_sar_i64(dest, src, tmp); 35726fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, dest, 0, a->len); 35730b1347d2SRichard Henderson } else { 3574bd792da3SRichard Henderson if (!a->d) { 35756fd0c7bcSRichard Henderson tcg_gen_ext32u_i64(dest, src); 3576bd792da3SRichard Henderson src = dest; 3577bd792da3SRichard Henderson } 35786fd0c7bcSRichard Henderson tcg_gen_shr_i64(dest, src, tmp); 35796fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, dest, 0, a->len); 35800b1347d2SRichard Henderson } 358130878590SRichard Henderson save_gpr(ctx, a->t, dest); 35820b1347d2SRichard Henderson 35830b1347d2SRichard Henderson /* Install the new nullification. */ 35840b1347d2SRichard Henderson cond_free(&ctx->null_cond); 358530878590SRichard Henderson if (a->c) { 3586bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 35870b1347d2SRichard Henderson } 358831234768SRichard Henderson return nullify_end(ctx); 35890b1347d2SRichard Henderson } 35900b1347d2SRichard Henderson 3591bd792da3SRichard Henderson static bool trans_extr_imm(DisasContext *ctx, arg_extr_imm *a) 35920b1347d2SRichard Henderson { 3593bd792da3SRichard Henderson unsigned len, cpos, width; 35946fd0c7bcSRichard Henderson TCGv_i64 dest, src; 35950b1347d2SRichard Henderson 3596bd792da3SRichard Henderson if (!ctx->is_pa20 && a->d) { 3597bd792da3SRichard Henderson return false; 3598bd792da3SRichard Henderson } 359930878590SRichard Henderson if (a->c) { 36000b1347d2SRichard Henderson nullify_over(ctx); 36010b1347d2SRichard Henderson } 36020b1347d2SRichard Henderson 3603bd792da3SRichard Henderson len = a->len; 3604bd792da3SRichard Henderson width = a->d ? 64 : 32; 3605bd792da3SRichard Henderson cpos = width - 1 - a->pos; 3606bd792da3SRichard Henderson if (cpos + len > width) { 3607bd792da3SRichard Henderson len = width - cpos; 3608bd792da3SRichard Henderson } 3609bd792da3SRichard Henderson 361030878590SRichard Henderson dest = dest_gpr(ctx, a->t); 361130878590SRichard Henderson src = load_gpr(ctx, a->r); 361230878590SRichard Henderson if (a->se) { 36136fd0c7bcSRichard Henderson tcg_gen_sextract_i64(dest, src, cpos, len); 36140b1347d2SRichard Henderson } else { 36156fd0c7bcSRichard Henderson tcg_gen_extract_i64(dest, src, cpos, len); 36160b1347d2SRichard Henderson } 361730878590SRichard Henderson save_gpr(ctx, a->t, dest); 36180b1347d2SRichard Henderson 36190b1347d2SRichard Henderson /* Install the new nullification. */ 36200b1347d2SRichard Henderson cond_free(&ctx->null_cond); 362130878590SRichard Henderson if (a->c) { 3622bd792da3SRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36230b1347d2SRichard Henderson } 362431234768SRichard Henderson return nullify_end(ctx); 36250b1347d2SRichard Henderson } 36260b1347d2SRichard Henderson 362772ae4f2bSRichard Henderson static bool trans_depi_imm(DisasContext *ctx, arg_depi_imm *a) 36280b1347d2SRichard Henderson { 362972ae4f2bSRichard Henderson unsigned len, width; 3630c53e401eSRichard Henderson uint64_t mask0, mask1; 36316fd0c7bcSRichard Henderson TCGv_i64 dest; 36320b1347d2SRichard Henderson 363372ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 363472ae4f2bSRichard Henderson return false; 363572ae4f2bSRichard Henderson } 363630878590SRichard Henderson if (a->c) { 36370b1347d2SRichard Henderson nullify_over(ctx); 36380b1347d2SRichard Henderson } 363972ae4f2bSRichard Henderson 364072ae4f2bSRichard Henderson len = a->len; 364172ae4f2bSRichard Henderson width = a->d ? 64 : 32; 364272ae4f2bSRichard Henderson if (a->cpos + len > width) { 364372ae4f2bSRichard Henderson len = width - a->cpos; 36440b1347d2SRichard Henderson } 36450b1347d2SRichard Henderson 364630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 364730878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 364830878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 36490b1347d2SRichard Henderson 365030878590SRichard Henderson if (a->nz) { 36516fd0c7bcSRichard Henderson TCGv_i64 src = load_gpr(ctx, a->t); 36526fd0c7bcSRichard Henderson tcg_gen_andi_i64(dest, src, mask1); 36536fd0c7bcSRichard Henderson tcg_gen_ori_i64(dest, dest, mask0); 36540b1347d2SRichard Henderson } else { 36556fd0c7bcSRichard Henderson tcg_gen_movi_i64(dest, mask0); 36560b1347d2SRichard Henderson } 365730878590SRichard Henderson save_gpr(ctx, a->t, dest); 36580b1347d2SRichard Henderson 36590b1347d2SRichard Henderson /* Install the new nullification. */ 36600b1347d2SRichard Henderson cond_free(&ctx->null_cond); 366130878590SRichard Henderson if (a->c) { 366272ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36630b1347d2SRichard Henderson } 366431234768SRichard Henderson return nullify_end(ctx); 36650b1347d2SRichard Henderson } 36660b1347d2SRichard Henderson 366772ae4f2bSRichard Henderson static bool trans_dep_imm(DisasContext *ctx, arg_dep_imm *a) 36680b1347d2SRichard Henderson { 366930878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 367072ae4f2bSRichard Henderson unsigned len, width; 36716fd0c7bcSRichard Henderson TCGv_i64 dest, val; 36720b1347d2SRichard Henderson 367372ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 367472ae4f2bSRichard Henderson return false; 367572ae4f2bSRichard Henderson } 367630878590SRichard Henderson if (a->c) { 36770b1347d2SRichard Henderson nullify_over(ctx); 36780b1347d2SRichard Henderson } 367972ae4f2bSRichard Henderson 368072ae4f2bSRichard Henderson len = a->len; 368172ae4f2bSRichard Henderson width = a->d ? 64 : 32; 368272ae4f2bSRichard Henderson if (a->cpos + len > width) { 368372ae4f2bSRichard Henderson len = width - a->cpos; 36840b1347d2SRichard Henderson } 36850b1347d2SRichard Henderson 368630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 368730878590SRichard Henderson val = load_gpr(ctx, a->r); 36880b1347d2SRichard Henderson if (rs == 0) { 36896fd0c7bcSRichard Henderson tcg_gen_deposit_z_i64(dest, val, a->cpos, len); 36900b1347d2SRichard Henderson } else { 36916fd0c7bcSRichard Henderson tcg_gen_deposit_i64(dest, cpu_gr[rs], val, a->cpos, len); 36920b1347d2SRichard Henderson } 369330878590SRichard Henderson save_gpr(ctx, a->t, dest); 36940b1347d2SRichard Henderson 36950b1347d2SRichard Henderson /* Install the new nullification. */ 36960b1347d2SRichard Henderson cond_free(&ctx->null_cond); 369730878590SRichard Henderson if (a->c) { 369872ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, a->c, a->d, dest); 36990b1347d2SRichard Henderson } 370031234768SRichard Henderson return nullify_end(ctx); 37010b1347d2SRichard Henderson } 37020b1347d2SRichard Henderson 370372ae4f2bSRichard Henderson static bool do_dep_sar(DisasContext *ctx, unsigned rt, unsigned c, 37046fd0c7bcSRichard Henderson bool d, bool nz, unsigned len, TCGv_i64 val) 37050b1347d2SRichard Henderson { 37060b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 370772ae4f2bSRichard Henderson unsigned widthm1 = d ? 63 : 31; 37086fd0c7bcSRichard Henderson TCGv_i64 mask, tmp, shift, dest; 3709c53e401eSRichard Henderson uint64_t msb = 1ULL << (len - 1); 37100b1347d2SRichard Henderson 37110b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 3712aac0f603SRichard Henderson shift = tcg_temp_new_i64(); 3713aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37140b1347d2SRichard Henderson 37150b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 37166fd0c7bcSRichard Henderson tcg_gen_andi_i64(shift, cpu_sar, widthm1); 37176fd0c7bcSRichard Henderson tcg_gen_xori_i64(shift, shift, widthm1); 37180b1347d2SRichard Henderson 3719aac0f603SRichard Henderson mask = tcg_temp_new_i64(); 37206fd0c7bcSRichard Henderson tcg_gen_movi_i64(mask, msb + (msb - 1)); 37216fd0c7bcSRichard Henderson tcg_gen_and_i64(tmp, val, mask); 37220b1347d2SRichard Henderson if (rs) { 37236fd0c7bcSRichard Henderson tcg_gen_shl_i64(mask, mask, shift); 37246fd0c7bcSRichard Henderson tcg_gen_shl_i64(tmp, tmp, shift); 37256fd0c7bcSRichard Henderson tcg_gen_andc_i64(dest, cpu_gr[rs], mask); 37266fd0c7bcSRichard Henderson tcg_gen_or_i64(dest, dest, tmp); 37270b1347d2SRichard Henderson } else { 37286fd0c7bcSRichard Henderson tcg_gen_shl_i64(dest, tmp, shift); 37290b1347d2SRichard Henderson } 37300b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 37310b1347d2SRichard Henderson 37320b1347d2SRichard Henderson /* Install the new nullification. */ 37330b1347d2SRichard Henderson cond_free(&ctx->null_cond); 37340b1347d2SRichard Henderson if (c) { 373572ae4f2bSRichard Henderson ctx->null_cond = do_sed_cond(ctx, c, d, dest); 37360b1347d2SRichard Henderson } 373731234768SRichard Henderson return nullify_end(ctx); 37380b1347d2SRichard Henderson } 37390b1347d2SRichard Henderson 374072ae4f2bSRichard Henderson static bool trans_dep_sar(DisasContext *ctx, arg_dep_sar *a) 374130878590SRichard Henderson { 374272ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 374372ae4f2bSRichard Henderson return false; 374472ae4f2bSRichard Henderson } 3745a6deecceSSven Schnelle if (a->c) { 3746a6deecceSSven Schnelle nullify_over(ctx); 3747a6deecceSSven Schnelle } 374872ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 374972ae4f2bSRichard Henderson load_gpr(ctx, a->r)); 375030878590SRichard Henderson } 375130878590SRichard Henderson 375272ae4f2bSRichard Henderson static bool trans_depi_sar(DisasContext *ctx, arg_depi_sar *a) 375330878590SRichard Henderson { 375472ae4f2bSRichard Henderson if (!ctx->is_pa20 && a->d) { 375572ae4f2bSRichard Henderson return false; 375672ae4f2bSRichard Henderson } 3757a6deecceSSven Schnelle if (a->c) { 3758a6deecceSSven Schnelle nullify_over(ctx); 3759a6deecceSSven Schnelle } 376072ae4f2bSRichard Henderson return do_dep_sar(ctx, a->t, a->c, a->d, a->nz, a->len, 37616fd0c7bcSRichard Henderson tcg_constant_i64(a->i)); 376230878590SRichard Henderson } 37630b1347d2SRichard Henderson 37648340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 376598cd9ca7SRichard Henderson { 37666fd0c7bcSRichard Henderson TCGv_i64 tmp; 376798cd9ca7SRichard Henderson 3768c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 376998cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 377098cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 377198cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 377298cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 377398cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 377498cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 377598cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 377698cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 37778340f534SRichard Henderson if (a->b == 0) { 37788340f534SRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 377998cd9ca7SRichard Henderson } 3780c301f34eSRichard Henderson #else 3781c301f34eSRichard Henderson nullify_over(ctx); 3782660eefe1SRichard Henderson #endif 3783660eefe1SRichard Henderson 3784aac0f603SRichard Henderson tmp = tcg_temp_new_i64(); 37856fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, load_gpr(ctx, a->b), a->disp); 3786660eefe1SRichard Henderson tmp = do_ibranch_priv(ctx, tmp); 3787c301f34eSRichard Henderson 3788c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 37898340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3790c301f34eSRichard Henderson #else 3791c301f34eSRichard Henderson TCGv_i64 new_spc = tcg_temp_new_i64(); 3792c301f34eSRichard Henderson 37938340f534SRichard Henderson load_spr(ctx, new_spc, a->sp); 37948340f534SRichard Henderson if (a->l) { 3795741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); 3796c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); 3797c301f34eSRichard Henderson } 37988340f534SRichard Henderson if (a->n && use_nullify_skip(ctx)) { 3799a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, tmp); 38006fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, 4); 3801a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3802c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, new_spc); 3803c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); 3804c301f34eSRichard Henderson } else { 3805741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3806c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3807c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3808c301f34eSRichard Henderson } 3809a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, tmp); 3810c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, new_spc); 38118340f534SRichard Henderson nullify_set(ctx, a->n); 3812c301f34eSRichard Henderson } 3813c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 381431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 381531234768SRichard Henderson return nullify_end(ctx); 3816c301f34eSRichard Henderson #endif 381798cd9ca7SRichard Henderson } 381898cd9ca7SRichard Henderson 38198340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 382098cd9ca7SRichard Henderson { 38218340f534SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n); 382298cd9ca7SRichard Henderson } 382398cd9ca7SRichard Henderson 38248340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 382543e05652SRichard Henderson { 3826c53e401eSRichard Henderson uint64_t dest = iaoq_dest(ctx, a->disp); 382743e05652SRichard Henderson 38286e5f5300SSven Schnelle nullify_over(ctx); 38296e5f5300SSven Schnelle 383043e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 383143e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 383243e05652SRichard Henderson * expensive to track. Real hardware will trap for 383343e05652SRichard Henderson * b gateway 383443e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 383543e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 383643e05652SRichard Henderson * diagnose the security hole 383743e05652SRichard Henderson * b gateway 383843e05652SRichard Henderson * b evil 383943e05652SRichard Henderson * in which instructions at evil would run with increased privs. 384043e05652SRichard Henderson */ 384143e05652SRichard Henderson if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) { 384243e05652SRichard Henderson return gen_illegal(ctx); 384343e05652SRichard Henderson } 384443e05652SRichard Henderson 384543e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 384643e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 384794956d7bSPhilippe Mathieu-Daudé int type = hppa_artype_for_page(cpu_env(ctx->cs), ctx->base.pc_next); 384843e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 384943e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 385043e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 385143e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 385243e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 385343e05652SRichard Henderson if (type < 0) { 385431234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 385531234768SRichard Henderson return true; 385643e05652SRichard Henderson } 385743e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 385843e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 385943e05652SRichard Henderson dest = deposit32(dest, 0, 2, type - 4); 386043e05652SRichard Henderson } 386143e05652SRichard Henderson } else { 386243e05652SRichard Henderson dest &= -4; /* priv = 0 */ 386343e05652SRichard Henderson } 386443e05652SRichard Henderson #endif 386543e05652SRichard Henderson 38666e5f5300SSven Schnelle if (a->l) { 38676fd0c7bcSRichard Henderson TCGv_i64 tmp = dest_gpr(ctx, a->l); 38686e5f5300SSven Schnelle if (ctx->privilege < 3) { 38696fd0c7bcSRichard Henderson tcg_gen_andi_i64(tmp, tmp, -4); 38706e5f5300SSven Schnelle } 38716fd0c7bcSRichard Henderson tcg_gen_ori_i64(tmp, tmp, ctx->privilege); 38726e5f5300SSven Schnelle save_gpr(ctx, a->l, tmp); 38736e5f5300SSven Schnelle } 38746e5f5300SSven Schnelle 38756e5f5300SSven Schnelle return do_dbranch(ctx, dest, 0, a->n); 387643e05652SRichard Henderson } 387743e05652SRichard Henderson 38788340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 387998cd9ca7SRichard Henderson { 3880b35aec85SRichard Henderson if (a->x) { 3881aac0f603SRichard Henderson TCGv_i64 tmp = tcg_temp_new_i64(); 38826fd0c7bcSRichard Henderson tcg_gen_shli_i64(tmp, load_gpr(ctx, a->x), 3); 38836fd0c7bcSRichard Henderson tcg_gen_addi_i64(tmp, tmp, ctx->iaoq_f + 8); 3884660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 38858340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3886b35aec85SRichard Henderson } else { 3887b35aec85SRichard Henderson /* BLR R0,RX is a good way to load PC+8 into RX. */ 3888b35aec85SRichard Henderson return do_dbranch(ctx, ctx->iaoq_f + 8, a->l, a->n); 3889b35aec85SRichard Henderson } 389098cd9ca7SRichard Henderson } 389198cd9ca7SRichard Henderson 38928340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 389398cd9ca7SRichard Henderson { 38946fd0c7bcSRichard Henderson TCGv_i64 dest; 389598cd9ca7SRichard Henderson 38968340f534SRichard Henderson if (a->x == 0) { 38978340f534SRichard Henderson dest = load_gpr(ctx, a->b); 389898cd9ca7SRichard Henderson } else { 3899aac0f603SRichard Henderson dest = tcg_temp_new_i64(); 39006fd0c7bcSRichard Henderson tcg_gen_shli_i64(dest, load_gpr(ctx, a->x), 3); 39016fd0c7bcSRichard Henderson tcg_gen_add_i64(dest, dest, load_gpr(ctx, a->b)); 390298cd9ca7SRichard Henderson } 3903660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 39048340f534SRichard Henderson return do_ibranch(ctx, dest, 0, a->n); 390598cd9ca7SRichard Henderson } 390698cd9ca7SRichard Henderson 39078340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 390898cd9ca7SRichard Henderson { 39096fd0c7bcSRichard Henderson TCGv_i64 dest; 391098cd9ca7SRichard Henderson 3911c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 39128340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 39138340f534SRichard Henderson return do_ibranch(ctx, dest, a->l, a->n); 3914c301f34eSRichard Henderson #else 3915c301f34eSRichard Henderson nullify_over(ctx); 39168340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3917c301f34eSRichard Henderson 3918741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3919c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3920c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3921c301f34eSRichard Henderson } 3922741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, dest); 3923c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); 39248340f534SRichard Henderson if (a->l) { 3925741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var); 3926c301f34eSRichard Henderson } 39278340f534SRichard Henderson nullify_set(ctx, a->n); 3928c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 392931234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 393031234768SRichard Henderson return nullify_end(ctx); 3931c301f34eSRichard Henderson #endif 393298cd9ca7SRichard Henderson } 393398cd9ca7SRichard Henderson 3934a8966ba7SRichard Henderson static bool trans_nopbts(DisasContext *ctx, arg_nopbts *a) 3935a8966ba7SRichard Henderson { 3936a8966ba7SRichard Henderson /* All branch target stack instructions implement as nop. */ 3937a8966ba7SRichard Henderson return ctx->is_pa20; 3938a8966ba7SRichard Henderson } 3939a8966ba7SRichard Henderson 39401ca74648SRichard Henderson /* 39411ca74648SRichard Henderson * Float class 0 39421ca74648SRichard Henderson */ 3943ebe9383cSRichard Henderson 39441ca74648SRichard Henderson static void gen_fcpy_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3945ebe9383cSRichard Henderson { 3946ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3947ebe9383cSRichard Henderson } 3948ebe9383cSRichard Henderson 394959f8c04bSHelge Deller static bool trans_fid_f(DisasContext *ctx, arg_fid_f *a) 395059f8c04bSHelge Deller { 3951a300dad3SRichard Henderson uint64_t ret; 3952a300dad3SRichard Henderson 3953c53e401eSRichard Henderson if (ctx->is_pa20) { 3954a300dad3SRichard Henderson ret = 0x13080000000000ULL; /* PA8700 (PCX-W2) */ 3955a300dad3SRichard Henderson } else { 3956a300dad3SRichard Henderson ret = 0x0f080000000000ULL; /* PA7300LC (PCX-L2) */ 3957a300dad3SRichard Henderson } 3958a300dad3SRichard Henderson 395959f8c04bSHelge Deller nullify_over(ctx); 3960a300dad3SRichard Henderson save_frd(0, tcg_constant_i64(ret)); 396159f8c04bSHelge Deller return nullify_end(ctx); 396259f8c04bSHelge Deller } 396359f8c04bSHelge Deller 39641ca74648SRichard Henderson static bool trans_fcpy_f(DisasContext *ctx, arg_fclass01 *a) 39651ca74648SRichard Henderson { 39661ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fcpy_f); 39671ca74648SRichard Henderson } 39681ca74648SRichard Henderson 3969ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3970ebe9383cSRichard Henderson { 3971ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 3972ebe9383cSRichard Henderson } 3973ebe9383cSRichard Henderson 39741ca74648SRichard Henderson static bool trans_fcpy_d(DisasContext *ctx, arg_fclass01 *a) 39751ca74648SRichard Henderson { 39761ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fcpy_d); 39771ca74648SRichard Henderson } 39781ca74648SRichard Henderson 39791ca74648SRichard Henderson static void gen_fabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3980ebe9383cSRichard Henderson { 3981ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 3982ebe9383cSRichard Henderson } 3983ebe9383cSRichard Henderson 39841ca74648SRichard Henderson static bool trans_fabs_f(DisasContext *ctx, arg_fclass01 *a) 39851ca74648SRichard Henderson { 39861ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fabs_f); 39871ca74648SRichard Henderson } 39881ca74648SRichard Henderson 3989ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3990ebe9383cSRichard Henderson { 3991ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 3992ebe9383cSRichard Henderson } 3993ebe9383cSRichard Henderson 39941ca74648SRichard Henderson static bool trans_fabs_d(DisasContext *ctx, arg_fclass01 *a) 39951ca74648SRichard Henderson { 39961ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fabs_d); 39971ca74648SRichard Henderson } 39981ca74648SRichard Henderson 39991ca74648SRichard Henderson static bool trans_fsqrt_f(DisasContext *ctx, arg_fclass01 *a) 40001ca74648SRichard Henderson { 40011ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fsqrt_s); 40021ca74648SRichard Henderson } 40031ca74648SRichard Henderson 40041ca74648SRichard Henderson static bool trans_fsqrt_d(DisasContext *ctx, arg_fclass01 *a) 40051ca74648SRichard Henderson { 40061ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fsqrt_d); 40071ca74648SRichard Henderson } 40081ca74648SRichard Henderson 40091ca74648SRichard Henderson static bool trans_frnd_f(DisasContext *ctx, arg_fclass01 *a) 40101ca74648SRichard Henderson { 40111ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_frnd_s); 40121ca74648SRichard Henderson } 40131ca74648SRichard Henderson 40141ca74648SRichard Henderson static bool trans_frnd_d(DisasContext *ctx, arg_fclass01 *a) 40151ca74648SRichard Henderson { 40161ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_frnd_d); 40171ca74648SRichard Henderson } 40181ca74648SRichard Henderson 40191ca74648SRichard Henderson static void gen_fneg_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4020ebe9383cSRichard Henderson { 4021ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 4022ebe9383cSRichard Henderson } 4023ebe9383cSRichard Henderson 40241ca74648SRichard Henderson static bool trans_fneg_f(DisasContext *ctx, arg_fclass01 *a) 40251ca74648SRichard Henderson { 40261ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fneg_f); 40271ca74648SRichard Henderson } 40281ca74648SRichard Henderson 4029ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4030ebe9383cSRichard Henderson { 4031ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 4032ebe9383cSRichard Henderson } 4033ebe9383cSRichard Henderson 40341ca74648SRichard Henderson static bool trans_fneg_d(DisasContext *ctx, arg_fclass01 *a) 40351ca74648SRichard Henderson { 40361ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fneg_d); 40371ca74648SRichard Henderson } 40381ca74648SRichard Henderson 40391ca74648SRichard Henderson static void gen_fnegabs_f(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 4040ebe9383cSRichard Henderson { 4041ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 4042ebe9383cSRichard Henderson } 4043ebe9383cSRichard Henderson 40441ca74648SRichard Henderson static bool trans_fnegabs_f(DisasContext *ctx, arg_fclass01 *a) 40451ca74648SRichard Henderson { 40461ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_fnegabs_f); 40471ca74648SRichard Henderson } 40481ca74648SRichard Henderson 4049ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 4050ebe9383cSRichard Henderson { 4051ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 4052ebe9383cSRichard Henderson } 4053ebe9383cSRichard Henderson 40541ca74648SRichard Henderson static bool trans_fnegabs_d(DisasContext *ctx, arg_fclass01 *a) 40551ca74648SRichard Henderson { 40561ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_fnegabs_d); 40571ca74648SRichard Henderson } 40581ca74648SRichard Henderson 40591ca74648SRichard Henderson /* 40601ca74648SRichard Henderson * Float class 1 40611ca74648SRichard Henderson */ 40621ca74648SRichard Henderson 40631ca74648SRichard Henderson static bool trans_fcnv_d_f(DisasContext *ctx, arg_fclass01 *a) 40641ca74648SRichard Henderson { 40651ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_s); 40661ca74648SRichard Henderson } 40671ca74648SRichard Henderson 40681ca74648SRichard Henderson static bool trans_fcnv_f_d(DisasContext *ctx, arg_fclass01 *a) 40691ca74648SRichard Henderson { 40701ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_d); 40711ca74648SRichard Henderson } 40721ca74648SRichard Henderson 40731ca74648SRichard Henderson static bool trans_fcnv_w_f(DisasContext *ctx, arg_fclass01 *a) 40741ca74648SRichard Henderson { 40751ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_w_s); 40761ca74648SRichard Henderson } 40771ca74648SRichard Henderson 40781ca74648SRichard Henderson static bool trans_fcnv_q_f(DisasContext *ctx, arg_fclass01 *a) 40791ca74648SRichard Henderson { 40801ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_dw_s); 40811ca74648SRichard Henderson } 40821ca74648SRichard Henderson 40831ca74648SRichard Henderson static bool trans_fcnv_w_d(DisasContext *ctx, arg_fclass01 *a) 40841ca74648SRichard Henderson { 40851ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_w_d); 40861ca74648SRichard Henderson } 40871ca74648SRichard Henderson 40881ca74648SRichard Henderson static bool trans_fcnv_q_d(DisasContext *ctx, arg_fclass01 *a) 40891ca74648SRichard Henderson { 40901ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_dw_d); 40911ca74648SRichard Henderson } 40921ca74648SRichard Henderson 40931ca74648SRichard Henderson static bool trans_fcnv_f_w(DisasContext *ctx, arg_fclass01 *a) 40941ca74648SRichard Henderson { 40951ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_w); 40961ca74648SRichard Henderson } 40971ca74648SRichard Henderson 40981ca74648SRichard Henderson static bool trans_fcnv_d_w(DisasContext *ctx, arg_fclass01 *a) 40991ca74648SRichard Henderson { 41001ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_w); 41011ca74648SRichard Henderson } 41021ca74648SRichard Henderson 41031ca74648SRichard Henderson static bool trans_fcnv_f_q(DisasContext *ctx, arg_fclass01 *a) 41041ca74648SRichard Henderson { 41051ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_dw); 41061ca74648SRichard Henderson } 41071ca74648SRichard Henderson 41081ca74648SRichard Henderson static bool trans_fcnv_d_q(DisasContext *ctx, arg_fclass01 *a) 41091ca74648SRichard Henderson { 41101ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_dw); 41111ca74648SRichard Henderson } 41121ca74648SRichard Henderson 41131ca74648SRichard Henderson static bool trans_fcnv_t_f_w(DisasContext *ctx, arg_fclass01 *a) 41141ca74648SRichard Henderson { 41151ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_w); 41161ca74648SRichard Henderson } 41171ca74648SRichard Henderson 41181ca74648SRichard Henderson static bool trans_fcnv_t_d_w(DisasContext *ctx, arg_fclass01 *a) 41191ca74648SRichard Henderson { 41201ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_w); 41211ca74648SRichard Henderson } 41221ca74648SRichard Henderson 41231ca74648SRichard Henderson static bool trans_fcnv_t_f_q(DisasContext *ctx, arg_fclass01 *a) 41241ca74648SRichard Henderson { 41251ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_dw); 41261ca74648SRichard Henderson } 41271ca74648SRichard Henderson 41281ca74648SRichard Henderson static bool trans_fcnv_t_d_q(DisasContext *ctx, arg_fclass01 *a) 41291ca74648SRichard Henderson { 41301ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_dw); 41311ca74648SRichard Henderson } 41321ca74648SRichard Henderson 41331ca74648SRichard Henderson static bool trans_fcnv_uw_f(DisasContext *ctx, arg_fclass01 *a) 41341ca74648SRichard Henderson { 41351ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_uw_s); 41361ca74648SRichard Henderson } 41371ca74648SRichard Henderson 41381ca74648SRichard Henderson static bool trans_fcnv_uq_f(DisasContext *ctx, arg_fclass01 *a) 41391ca74648SRichard Henderson { 41401ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_udw_s); 41411ca74648SRichard Henderson } 41421ca74648SRichard Henderson 41431ca74648SRichard Henderson static bool trans_fcnv_uw_d(DisasContext *ctx, arg_fclass01 *a) 41441ca74648SRichard Henderson { 41451ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_uw_d); 41461ca74648SRichard Henderson } 41471ca74648SRichard Henderson 41481ca74648SRichard Henderson static bool trans_fcnv_uq_d(DisasContext *ctx, arg_fclass01 *a) 41491ca74648SRichard Henderson { 41501ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_udw_d); 41511ca74648SRichard Henderson } 41521ca74648SRichard Henderson 41531ca74648SRichard Henderson static bool trans_fcnv_f_uw(DisasContext *ctx, arg_fclass01 *a) 41541ca74648SRichard Henderson { 41551ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_s_uw); 41561ca74648SRichard Henderson } 41571ca74648SRichard Henderson 41581ca74648SRichard Henderson static bool trans_fcnv_d_uw(DisasContext *ctx, arg_fclass01 *a) 41591ca74648SRichard Henderson { 41601ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_d_uw); 41611ca74648SRichard Henderson } 41621ca74648SRichard Henderson 41631ca74648SRichard Henderson static bool trans_fcnv_f_uq(DisasContext *ctx, arg_fclass01 *a) 41641ca74648SRichard Henderson { 41651ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_s_udw); 41661ca74648SRichard Henderson } 41671ca74648SRichard Henderson 41681ca74648SRichard Henderson static bool trans_fcnv_d_uq(DisasContext *ctx, arg_fclass01 *a) 41691ca74648SRichard Henderson { 41701ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_d_udw); 41711ca74648SRichard Henderson } 41721ca74648SRichard Henderson 41731ca74648SRichard Henderson static bool trans_fcnv_t_f_uw(DisasContext *ctx, arg_fclass01 *a) 41741ca74648SRichard Henderson { 41751ca74648SRichard Henderson return do_fop_wew(ctx, a->t, a->r, gen_helper_fcnv_t_s_uw); 41761ca74648SRichard Henderson } 41771ca74648SRichard Henderson 41781ca74648SRichard Henderson static bool trans_fcnv_t_d_uw(DisasContext *ctx, arg_fclass01 *a) 41791ca74648SRichard Henderson { 41801ca74648SRichard Henderson return do_fop_wed(ctx, a->t, a->r, gen_helper_fcnv_t_d_uw); 41811ca74648SRichard Henderson } 41821ca74648SRichard Henderson 41831ca74648SRichard Henderson static bool trans_fcnv_t_f_uq(DisasContext *ctx, arg_fclass01 *a) 41841ca74648SRichard Henderson { 41851ca74648SRichard Henderson return do_fop_dew(ctx, a->t, a->r, gen_helper_fcnv_t_s_udw); 41861ca74648SRichard Henderson } 41871ca74648SRichard Henderson 41881ca74648SRichard Henderson static bool trans_fcnv_t_d_uq(DisasContext *ctx, arg_fclass01 *a) 41891ca74648SRichard Henderson { 41901ca74648SRichard Henderson return do_fop_ded(ctx, a->t, a->r, gen_helper_fcnv_t_d_udw); 41911ca74648SRichard Henderson } 41921ca74648SRichard Henderson 41931ca74648SRichard Henderson /* 41941ca74648SRichard Henderson * Float class 2 41951ca74648SRichard Henderson */ 41961ca74648SRichard Henderson 41971ca74648SRichard Henderson static bool trans_fcmp_f(DisasContext *ctx, arg_fclass2 *a) 4198ebe9383cSRichard Henderson { 4199ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 4200ebe9383cSRichard Henderson 4201ebe9383cSRichard Henderson nullify_over(ctx); 4202ebe9383cSRichard Henderson 42031ca74648SRichard Henderson ta = load_frw0_i32(a->r1); 42041ca74648SRichard Henderson tb = load_frw0_i32(a->r2); 420529dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 420629dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4207ebe9383cSRichard Henderson 4208ad75a51eSRichard Henderson gen_helper_fcmp_s(tcg_env, ta, tb, ty, tc); 4209ebe9383cSRichard Henderson 42101ca74648SRichard Henderson return nullify_end(ctx); 4211ebe9383cSRichard Henderson } 4212ebe9383cSRichard Henderson 42131ca74648SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, arg_fclass2 *a) 4214ebe9383cSRichard Henderson { 4215ebe9383cSRichard Henderson TCGv_i64 ta, tb; 4216ebe9383cSRichard Henderson TCGv_i32 tc, ty; 4217ebe9383cSRichard Henderson 4218ebe9383cSRichard Henderson nullify_over(ctx); 4219ebe9383cSRichard Henderson 42201ca74648SRichard Henderson ta = load_frd0(a->r1); 42211ca74648SRichard Henderson tb = load_frd0(a->r2); 422229dd6f64SRichard Henderson ty = tcg_constant_i32(a->y); 422329dd6f64SRichard Henderson tc = tcg_constant_i32(a->c); 4224ebe9383cSRichard Henderson 4225ad75a51eSRichard Henderson gen_helper_fcmp_d(tcg_env, ta, tb, ty, tc); 4226ebe9383cSRichard Henderson 422731234768SRichard Henderson return nullify_end(ctx); 4228ebe9383cSRichard Henderson } 4229ebe9383cSRichard Henderson 42301ca74648SRichard Henderson static bool trans_ftest(DisasContext *ctx, arg_ftest *a) 4231ebe9383cSRichard Henderson { 42326fd0c7bcSRichard Henderson TCGv_i64 t; 4233ebe9383cSRichard Henderson 4234ebe9383cSRichard Henderson nullify_over(ctx); 4235ebe9383cSRichard Henderson 4236aac0f603SRichard Henderson t = tcg_temp_new_i64(); 42376fd0c7bcSRichard Henderson tcg_gen_ld32u_i64(t, tcg_env, offsetof(CPUHPPAState, fr0_shadow)); 4238ebe9383cSRichard Henderson 42391ca74648SRichard Henderson if (a->y == 1) { 4240ebe9383cSRichard Henderson int mask; 4241ebe9383cSRichard Henderson bool inv = false; 4242ebe9383cSRichard Henderson 42431ca74648SRichard Henderson switch (a->c) { 4244ebe9383cSRichard Henderson case 0: /* simple */ 42456fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, 0x4000000); 4246ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 4247ebe9383cSRichard Henderson goto done; 4248ebe9383cSRichard Henderson case 2: /* rej */ 4249ebe9383cSRichard Henderson inv = true; 4250ebe9383cSRichard Henderson /* fallthru */ 4251ebe9383cSRichard Henderson case 1: /* acc */ 4252ebe9383cSRichard Henderson mask = 0x43ff800; 4253ebe9383cSRichard Henderson break; 4254ebe9383cSRichard Henderson case 6: /* rej8 */ 4255ebe9383cSRichard Henderson inv = true; 4256ebe9383cSRichard Henderson /* fallthru */ 4257ebe9383cSRichard Henderson case 5: /* acc8 */ 4258ebe9383cSRichard Henderson mask = 0x43f8000; 4259ebe9383cSRichard Henderson break; 4260ebe9383cSRichard Henderson case 9: /* acc6 */ 4261ebe9383cSRichard Henderson mask = 0x43e0000; 4262ebe9383cSRichard Henderson break; 4263ebe9383cSRichard Henderson case 13: /* acc4 */ 4264ebe9383cSRichard Henderson mask = 0x4380000; 4265ebe9383cSRichard Henderson break; 4266ebe9383cSRichard Henderson case 17: /* acc2 */ 4267ebe9383cSRichard Henderson mask = 0x4200000; 4268ebe9383cSRichard Henderson break; 4269ebe9383cSRichard Henderson default: 42701ca74648SRichard Henderson gen_illegal(ctx); 42711ca74648SRichard Henderson return true; 4272ebe9383cSRichard Henderson } 4273ebe9383cSRichard Henderson if (inv) { 42746fd0c7bcSRichard Henderson TCGv_i64 c = tcg_constant_i64(mask); 42756fd0c7bcSRichard Henderson tcg_gen_or_i64(t, t, c); 4276ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 4277ebe9383cSRichard Henderson } else { 42786fd0c7bcSRichard Henderson tcg_gen_andi_i64(t, t, mask); 4279ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 4280ebe9383cSRichard Henderson } 42811ca74648SRichard Henderson } else { 42821ca74648SRichard Henderson unsigned cbit = (a->y ^ 1) - 1; 42831ca74648SRichard Henderson 42846fd0c7bcSRichard Henderson tcg_gen_extract_i64(t, t, 21 - cbit, 1); 42851ca74648SRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 42861ca74648SRichard Henderson } 42871ca74648SRichard Henderson 4288ebe9383cSRichard Henderson done: 428931234768SRichard Henderson return nullify_end(ctx); 4290ebe9383cSRichard Henderson } 4291ebe9383cSRichard Henderson 42921ca74648SRichard Henderson /* 42931ca74648SRichard Henderson * Float class 2 42941ca74648SRichard Henderson */ 42951ca74648SRichard Henderson 42961ca74648SRichard Henderson static bool trans_fadd_f(DisasContext *ctx, arg_fclass3 *a) 4297ebe9383cSRichard Henderson { 42981ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fadd_s); 42991ca74648SRichard Henderson } 43001ca74648SRichard Henderson 43011ca74648SRichard Henderson static bool trans_fadd_d(DisasContext *ctx, arg_fclass3 *a) 43021ca74648SRichard Henderson { 43031ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fadd_d); 43041ca74648SRichard Henderson } 43051ca74648SRichard Henderson 43061ca74648SRichard Henderson static bool trans_fsub_f(DisasContext *ctx, arg_fclass3 *a) 43071ca74648SRichard Henderson { 43081ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fsub_s); 43091ca74648SRichard Henderson } 43101ca74648SRichard Henderson 43111ca74648SRichard Henderson static bool trans_fsub_d(DisasContext *ctx, arg_fclass3 *a) 43121ca74648SRichard Henderson { 43131ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fsub_d); 43141ca74648SRichard Henderson } 43151ca74648SRichard Henderson 43161ca74648SRichard Henderson static bool trans_fmpy_f(DisasContext *ctx, arg_fclass3 *a) 43171ca74648SRichard Henderson { 43181ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_s); 43191ca74648SRichard Henderson } 43201ca74648SRichard Henderson 43211ca74648SRichard Henderson static bool trans_fmpy_d(DisasContext *ctx, arg_fclass3 *a) 43221ca74648SRichard Henderson { 43231ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fmpy_d); 43241ca74648SRichard Henderson } 43251ca74648SRichard Henderson 43261ca74648SRichard Henderson static bool trans_fdiv_f(DisasContext *ctx, arg_fclass3 *a) 43271ca74648SRichard Henderson { 43281ca74648SRichard Henderson return do_fop_weww(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_s); 43291ca74648SRichard Henderson } 43301ca74648SRichard Henderson 43311ca74648SRichard Henderson static bool trans_fdiv_d(DisasContext *ctx, arg_fclass3 *a) 43321ca74648SRichard Henderson { 43331ca74648SRichard Henderson return do_fop_dedd(ctx, a->t, a->r1, a->r2, gen_helper_fdiv_d); 43341ca74648SRichard Henderson } 43351ca74648SRichard Henderson 43361ca74648SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, arg_xmpyu *a) 43371ca74648SRichard Henderson { 43381ca74648SRichard Henderson TCGv_i64 x, y; 4339ebe9383cSRichard Henderson 4340ebe9383cSRichard Henderson nullify_over(ctx); 4341ebe9383cSRichard Henderson 43421ca74648SRichard Henderson x = load_frw0_i64(a->r1); 43431ca74648SRichard Henderson y = load_frw0_i64(a->r2); 43441ca74648SRichard Henderson tcg_gen_mul_i64(x, x, y); 43451ca74648SRichard Henderson save_frd(a->t, x); 4346ebe9383cSRichard Henderson 434731234768SRichard Henderson return nullify_end(ctx); 4348ebe9383cSRichard Henderson } 4349ebe9383cSRichard Henderson 4350ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4351ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4352ebe9383cSRichard Henderson { 4353ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4354ebe9383cSRichard Henderson } 4355ebe9383cSRichard Henderson 4356b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4357ebe9383cSRichard Henderson { 4358b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4359b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4360b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4361b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4362b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4363ebe9383cSRichard Henderson 4364ebe9383cSRichard Henderson nullify_over(ctx); 4365ebe9383cSRichard Henderson 4366ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4367ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4368ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4369ebe9383cSRichard Henderson 437031234768SRichard Henderson return nullify_end(ctx); 4371ebe9383cSRichard Henderson } 4372ebe9383cSRichard Henderson 4373b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4374b1e2af57SRichard Henderson { 4375b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4376b1e2af57SRichard Henderson } 4377b1e2af57SRichard Henderson 4378b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4379b1e2af57SRichard Henderson { 4380b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4381b1e2af57SRichard Henderson } 4382b1e2af57SRichard Henderson 4383b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4384b1e2af57SRichard Henderson { 4385b1e2af57SRichard Henderson nullify_over(ctx); 4386b1e2af57SRichard Henderson 4387b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4388b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4389b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4390b1e2af57SRichard Henderson 4391b1e2af57SRichard Henderson return nullify_end(ctx); 4392b1e2af57SRichard Henderson } 4393b1e2af57SRichard Henderson 4394b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4395b1e2af57SRichard Henderson { 4396b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4397b1e2af57SRichard Henderson } 4398b1e2af57SRichard Henderson 4399b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4400b1e2af57SRichard Henderson { 4401b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4402b1e2af57SRichard Henderson } 4403b1e2af57SRichard Henderson 4404c3bad4f8SRichard Henderson static bool trans_fmpyfadd_f(DisasContext *ctx, arg_fmpyfadd_f *a) 4405ebe9383cSRichard Henderson { 4406c3bad4f8SRichard Henderson TCGv_i32 x, y, z; 4407ebe9383cSRichard Henderson 4408ebe9383cSRichard Henderson nullify_over(ctx); 4409c3bad4f8SRichard Henderson x = load_frw0_i32(a->rm1); 4410c3bad4f8SRichard Henderson y = load_frw0_i32(a->rm2); 4411c3bad4f8SRichard Henderson z = load_frw0_i32(a->ra3); 4412ebe9383cSRichard Henderson 4413c3bad4f8SRichard Henderson if (a->neg) { 4414ad75a51eSRichard Henderson gen_helper_fmpynfadd_s(x, tcg_env, x, y, z); 4415ebe9383cSRichard Henderson } else { 4416ad75a51eSRichard Henderson gen_helper_fmpyfadd_s(x, tcg_env, x, y, z); 4417ebe9383cSRichard Henderson } 4418ebe9383cSRichard Henderson 4419c3bad4f8SRichard Henderson save_frw_i32(a->t, x); 442031234768SRichard Henderson return nullify_end(ctx); 4421ebe9383cSRichard Henderson } 4422ebe9383cSRichard Henderson 4423c3bad4f8SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, arg_fmpyfadd_d *a) 4424ebe9383cSRichard Henderson { 4425c3bad4f8SRichard Henderson TCGv_i64 x, y, z; 4426ebe9383cSRichard Henderson 4427ebe9383cSRichard Henderson nullify_over(ctx); 4428c3bad4f8SRichard Henderson x = load_frd0(a->rm1); 4429c3bad4f8SRichard Henderson y = load_frd0(a->rm2); 4430c3bad4f8SRichard Henderson z = load_frd0(a->ra3); 4431ebe9383cSRichard Henderson 4432c3bad4f8SRichard Henderson if (a->neg) { 4433ad75a51eSRichard Henderson gen_helper_fmpynfadd_d(x, tcg_env, x, y, z); 4434ebe9383cSRichard Henderson } else { 4435ad75a51eSRichard Henderson gen_helper_fmpyfadd_d(x, tcg_env, x, y, z); 4436ebe9383cSRichard Henderson } 4437ebe9383cSRichard Henderson 4438c3bad4f8SRichard Henderson save_frd(a->t, x); 443931234768SRichard Henderson return nullify_end(ctx); 4440ebe9383cSRichard Henderson } 4441ebe9383cSRichard Henderson 444215da177bSSven Schnelle static bool trans_diag(DisasContext *ctx, arg_diag *a) 444315da177bSSven Schnelle { 4444cf6b28d4SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 4445cf6b28d4SHelge Deller #ifndef CONFIG_USER_ONLY 4446cf6b28d4SHelge Deller if (a->i == 0x100) { 4447cf6b28d4SHelge Deller /* emulate PDC BTLB, called by SeaBIOS-hppa */ 4448ad75a51eSRichard Henderson nullify_over(ctx); 4449ad75a51eSRichard Henderson gen_helper_diag_btlb(tcg_env); 4450cf6b28d4SHelge Deller return nullify_end(ctx); 445115da177bSSven Schnelle } 4452dbca0835SHelge Deller if (a->i == 0x101) { 4453dbca0835SHelge Deller /* print char in %r26 to first serial console, used by SeaBIOS-hppa */ 4454dbca0835SHelge Deller nullify_over(ctx); 4455dbca0835SHelge Deller gen_helper_diag_console_output(tcg_env); 4456dbca0835SHelge Deller return nullify_end(ctx); 4457dbca0835SHelge Deller } 4458ad75a51eSRichard Henderson #endif 4459ad75a51eSRichard Henderson qemu_log_mask(LOG_UNIMP, "DIAG opcode 0x%04x ignored\n", a->i); 4460ad75a51eSRichard Henderson return true; 4461ad75a51eSRichard Henderson } 446215da177bSSven Schnelle 4463b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 446461766fe9SRichard Henderson { 446551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4466f764718dSRichard Henderson int bound; 446761766fe9SRichard Henderson 446851b061fbSRichard Henderson ctx->cs = cs; 4469494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 4470bd6243a3SRichard Henderson ctx->is_pa20 = hppa_is_pa20(cpu_env(cs)); 44713d68ee7bSRichard Henderson 44723d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 4473c01e5dfbSHelge Deller ctx->privilege = MMU_IDX_TO_PRIV(MMU_USER_IDX); 44743d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 4475c01e5dfbSHelge Deller ctx->iaoq_f = ctx->base.pc_first | ctx->privilege; 4476c01e5dfbSHelge Deller ctx->iaoq_b = ctx->base.tb->cs_base | ctx->privilege; 4477217d1a5eSRichard Henderson ctx->unalign = (ctx->tb_flags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN); 4478c301f34eSRichard Henderson #else 4479494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4480bb67ec32SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D 4481bb67ec32SRichard Henderson ? PRIV_P_TO_MMU_IDX(ctx->privilege, ctx->tb_flags & PSW_P) 4482451d993dSRichard Henderson : ctx->tb_flags & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX); 44833d68ee7bSRichard Henderson 4484c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4485c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4486c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4487c301f34eSRichard Henderson int32_t diff = cs_base; 4488c301f34eSRichard Henderson 4489c301f34eSRichard Henderson ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4490c301f34eSRichard Henderson ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); 4491c301f34eSRichard Henderson #endif 449251b061fbSRichard Henderson ctx->iaoq_n = -1; 4493f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 449461766fe9SRichard Henderson 4495a4db4a78SRichard Henderson ctx->zero = tcg_constant_i64(0); 4496a4db4a78SRichard Henderson 44973d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 44983d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4499b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 450061766fe9SRichard Henderson } 450161766fe9SRichard Henderson 450251b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 450351b061fbSRichard Henderson { 450451b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 450561766fe9SRichard Henderson 45063d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 450751b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 450851b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4509494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 451051b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 451151b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4512129e9cc3SRichard Henderson } 451351b061fbSRichard Henderson ctx->null_lab = NULL; 451461766fe9SRichard Henderson } 451561766fe9SRichard Henderson 451651b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 451751b061fbSRichard Henderson { 451851b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 451951b061fbSRichard Henderson 4520f5b5c857SRichard Henderson tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b, 0); 4521f5b5c857SRichard Henderson ctx->insn_start = tcg_last_op(); 452251b061fbSRichard Henderson } 452351b061fbSRichard Henderson 452451b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 452551b061fbSRichard Henderson { 452651b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4527b77af26eSRichard Henderson CPUHPPAState *env = cpu_env(cs); 452851b061fbSRichard Henderson DisasJumpType ret; 452951b061fbSRichard Henderson 453051b061fbSRichard Henderson /* Execute one insn. */ 4531ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4532c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 453331234768SRichard Henderson do_page_zero(ctx); 453431234768SRichard Henderson ret = ctx->base.is_jmp; 4535869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4536ba1d0b44SRichard Henderson } else 4537ba1d0b44SRichard Henderson #endif 4538ba1d0b44SRichard Henderson { 453961766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 454061766fe9SRichard Henderson the page permissions for execute. */ 45414e116893SIlya Leoshkevich uint32_t insn = translator_ldl(env, &ctx->base, ctx->base.pc_next); 454261766fe9SRichard Henderson 454361766fe9SRichard Henderson /* Set up the IA queue for the next insn. 454461766fe9SRichard Henderson This will be overwritten by a branch. */ 454551b061fbSRichard Henderson if (ctx->iaoq_b == -1) { 454651b061fbSRichard Henderson ctx->iaoq_n = -1; 4547aac0f603SRichard Henderson ctx->iaoq_n_var = tcg_temp_new_i64(); 45486fd0c7bcSRichard Henderson tcg_gen_addi_i64(ctx->iaoq_n_var, cpu_iaoq_b, 4); 454961766fe9SRichard Henderson } else { 455051b061fbSRichard Henderson ctx->iaoq_n = ctx->iaoq_b + 4; 4551f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 455261766fe9SRichard Henderson } 455361766fe9SRichard Henderson 455451b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 455551b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4556869051eaSRichard Henderson ret = DISAS_NEXT; 4557129e9cc3SRichard Henderson } else { 45581a19da0dSRichard Henderson ctx->insn = insn; 455931274b46SRichard Henderson if (!decode(ctx, insn)) { 456031274b46SRichard Henderson gen_illegal(ctx); 456131274b46SRichard Henderson } 456231234768SRichard Henderson ret = ctx->base.is_jmp; 456351b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4564129e9cc3SRichard Henderson } 456561766fe9SRichard Henderson } 456661766fe9SRichard Henderson 45673d68ee7bSRichard Henderson /* Advance the insn queue. Note that this check also detects 45683d68ee7bSRichard Henderson a priority change within the instruction queue. */ 456951b061fbSRichard Henderson if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 4570c301f34eSRichard Henderson if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 4571c301f34eSRichard Henderson && use_goto_tb(ctx, ctx->iaoq_b) 4572c301f34eSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4573c301f34eSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 457451b061fbSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 457551b061fbSRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 457631234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_NORETURN; 4577129e9cc3SRichard Henderson } else { 457831234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE; 457961766fe9SRichard Henderson } 4580129e9cc3SRichard Henderson } 458151b061fbSRichard Henderson ctx->iaoq_f = ctx->iaoq_b; 458251b061fbSRichard Henderson ctx->iaoq_b = ctx->iaoq_n; 4583c301f34eSRichard Henderson ctx->base.pc_next += 4; 458461766fe9SRichard Henderson 4585c5d0aec2SRichard Henderson switch (ret) { 4586c5d0aec2SRichard Henderson case DISAS_NORETURN: 4587c5d0aec2SRichard Henderson case DISAS_IAQ_N_UPDATED: 4588c5d0aec2SRichard Henderson break; 4589c5d0aec2SRichard Henderson 4590c5d0aec2SRichard Henderson case DISAS_NEXT: 4591c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE: 4592c5d0aec2SRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 459351b061fbSRichard Henderson if (ctx->iaoq_f == -1) { 4594a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, -1, cpu_iaoq_b); 4595741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 4596c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY 4597c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 4598c301f34eSRichard Henderson #endif 459951b061fbSRichard Henderson nullify_save(ctx); 4600c5d0aec2SRichard Henderson ctx->base.is_jmp = (ret == DISAS_IAQ_N_STALE_EXIT 4601c5d0aec2SRichard Henderson ? DISAS_EXIT 4602c5d0aec2SRichard Henderson : DISAS_IAQ_N_UPDATED); 460351b061fbSRichard Henderson } else if (ctx->iaoq_b == -1) { 4604a0180973SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, -1, ctx->iaoq_n_var); 460561766fe9SRichard Henderson } 4606c5d0aec2SRichard Henderson break; 4607c5d0aec2SRichard Henderson 4608c5d0aec2SRichard Henderson default: 4609c5d0aec2SRichard Henderson g_assert_not_reached(); 4610c5d0aec2SRichard Henderson } 461161766fe9SRichard Henderson } 461261766fe9SRichard Henderson 461351b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 461451b061fbSRichard Henderson { 461551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4616e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 461751b061fbSRichard Henderson 4618e1b5a5edSRichard Henderson switch (is_jmp) { 4619869051eaSRichard Henderson case DISAS_NORETURN: 462061766fe9SRichard Henderson break; 462151b061fbSRichard Henderson case DISAS_TOO_MANY: 4622869051eaSRichard Henderson case DISAS_IAQ_N_STALE: 4623e1b5a5edSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 4624741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 4625741322f4SRichard Henderson copy_iaoq_entry(ctx, cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 462651b061fbSRichard Henderson nullify_save(ctx); 462761766fe9SRichard Henderson /* FALLTHRU */ 4628869051eaSRichard Henderson case DISAS_IAQ_N_UPDATED: 46298532a14eSRichard Henderson if (is_jmp != DISAS_IAQ_N_STALE_EXIT) { 46307f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 46318532a14eSRichard Henderson break; 463261766fe9SRichard Henderson } 4633c5d0aec2SRichard Henderson /* FALLTHRU */ 4634c5d0aec2SRichard Henderson case DISAS_EXIT: 4635c5d0aec2SRichard Henderson tcg_gen_exit_tb(NULL, 0); 463661766fe9SRichard Henderson break; 463761766fe9SRichard Henderson default: 463851b061fbSRichard Henderson g_assert_not_reached(); 463961766fe9SRichard Henderson } 464051b061fbSRichard Henderson } 464161766fe9SRichard Henderson 46428eb806a7SRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, 46438eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 464451b061fbSRichard Henderson { 4645c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 464661766fe9SRichard Henderson 4647ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4648ba1d0b44SRichard Henderson switch (pc) { 46497ad439dfSRichard Henderson case 0x00: 46508eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000000: (null)\n"); 4651ba1d0b44SRichard Henderson return; 46527ad439dfSRichard Henderson case 0xb0: 46538eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000b0: light-weight-syscall\n"); 4654ba1d0b44SRichard Henderson return; 46557ad439dfSRichard Henderson case 0xe0: 46568eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4657ba1d0b44SRichard Henderson return; 46587ad439dfSRichard Henderson case 0x100: 46598eb806a7SRichard Henderson fprintf(logfile, "IN:\n0x00000100: syscall\n"); 4660ba1d0b44SRichard Henderson return; 46617ad439dfSRichard Henderson } 4662ba1d0b44SRichard Henderson #endif 4663ba1d0b44SRichard Henderson 46648eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(pc)); 46658eb806a7SRichard Henderson target_disas(logfile, cs, pc, dcbase->tb->size); 466661766fe9SRichard Henderson } 466751b061fbSRichard Henderson 466851b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 466951b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 467051b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 467151b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 467251b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 467351b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 467451b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 467551b061fbSRichard Henderson }; 467651b061fbSRichard Henderson 4677597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 467832f0c394SAnton Johansson vaddr pc, void *host_pc) 467951b061fbSRichard Henderson { 468051b061fbSRichard Henderson DisasContext ctx; 4681306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &hppa_tr_ops, &ctx.base); 468261766fe9SRichard Henderson } 4683