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 961766fe9SRichard Henderson * version 2 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" 2561766fe9SRichard Henderson #include "tcg-op.h" 2661766fe9SRichard Henderson #include "exec/cpu_ldst.h" 2761766fe9SRichard Henderson #include "exec/helper-proto.h" 2861766fe9SRichard Henderson #include "exec/helper-gen.h" 29869051eaSRichard Henderson #include "exec/translator.h" 3061766fe9SRichard Henderson #include "trace-tcg.h" 3161766fe9SRichard Henderson #include "exec/log.h" 3261766fe9SRichard Henderson 33eaa3783bSRichard Henderson /* Since we have a distinction between register size and address size, 34eaa3783bSRichard Henderson we need to redefine all of these. */ 35eaa3783bSRichard Henderson 36eaa3783bSRichard Henderson #undef TCGv 37eaa3783bSRichard Henderson #undef tcg_temp_new 38eaa3783bSRichard Henderson #undef tcg_global_reg_new 39eaa3783bSRichard Henderson #undef tcg_global_mem_new 40eaa3783bSRichard Henderson #undef tcg_temp_local_new 41eaa3783bSRichard Henderson #undef tcg_temp_free 42eaa3783bSRichard Henderson 43eaa3783bSRichard Henderson #if TARGET_LONG_BITS == 64 44eaa3783bSRichard Henderson #define TCGv_tl TCGv_i64 45eaa3783bSRichard Henderson #define tcg_temp_new_tl tcg_temp_new_i64 46eaa3783bSRichard Henderson #define tcg_temp_free_tl tcg_temp_free_i64 47eaa3783bSRichard Henderson #if TARGET_REGISTER_BITS == 64 48eaa3783bSRichard Henderson #define tcg_gen_extu_reg_tl tcg_gen_mov_i64 49eaa3783bSRichard Henderson #else 50eaa3783bSRichard Henderson #define tcg_gen_extu_reg_tl tcg_gen_extu_i32_i64 51eaa3783bSRichard Henderson #endif 52eaa3783bSRichard Henderson #else 53eaa3783bSRichard Henderson #define TCGv_tl TCGv_i32 54eaa3783bSRichard Henderson #define tcg_temp_new_tl tcg_temp_new_i32 55eaa3783bSRichard Henderson #define tcg_temp_free_tl tcg_temp_free_i32 56eaa3783bSRichard Henderson #define tcg_gen_extu_reg_tl tcg_gen_mov_i32 57eaa3783bSRichard Henderson #endif 58eaa3783bSRichard Henderson 59eaa3783bSRichard Henderson #if TARGET_REGISTER_BITS == 64 60eaa3783bSRichard Henderson #define TCGv_reg TCGv_i64 61eaa3783bSRichard Henderson 62eaa3783bSRichard Henderson #define tcg_temp_new tcg_temp_new_i64 63eaa3783bSRichard Henderson #define tcg_global_reg_new tcg_global_reg_new_i64 64eaa3783bSRichard Henderson #define tcg_global_mem_new tcg_global_mem_new_i64 65eaa3783bSRichard Henderson #define tcg_temp_local_new tcg_temp_local_new_i64 66eaa3783bSRichard Henderson #define tcg_temp_free tcg_temp_free_i64 67eaa3783bSRichard Henderson 68eaa3783bSRichard Henderson #define tcg_gen_movi_reg tcg_gen_movi_i64 69eaa3783bSRichard Henderson #define tcg_gen_mov_reg tcg_gen_mov_i64 70eaa3783bSRichard Henderson #define tcg_gen_ld8u_reg tcg_gen_ld8u_i64 71eaa3783bSRichard Henderson #define tcg_gen_ld8s_reg tcg_gen_ld8s_i64 72eaa3783bSRichard Henderson #define tcg_gen_ld16u_reg tcg_gen_ld16u_i64 73eaa3783bSRichard Henderson #define tcg_gen_ld16s_reg tcg_gen_ld16s_i64 74eaa3783bSRichard Henderson #define tcg_gen_ld32u_reg tcg_gen_ld32u_i64 75eaa3783bSRichard Henderson #define tcg_gen_ld32s_reg tcg_gen_ld32s_i64 76eaa3783bSRichard Henderson #define tcg_gen_ld_reg tcg_gen_ld_i64 77eaa3783bSRichard Henderson #define tcg_gen_st8_reg tcg_gen_st8_i64 78eaa3783bSRichard Henderson #define tcg_gen_st16_reg tcg_gen_st16_i64 79eaa3783bSRichard Henderson #define tcg_gen_st32_reg tcg_gen_st32_i64 80eaa3783bSRichard Henderson #define tcg_gen_st_reg tcg_gen_st_i64 81eaa3783bSRichard Henderson #define tcg_gen_add_reg tcg_gen_add_i64 82eaa3783bSRichard Henderson #define tcg_gen_addi_reg tcg_gen_addi_i64 83eaa3783bSRichard Henderson #define tcg_gen_sub_reg tcg_gen_sub_i64 84eaa3783bSRichard Henderson #define tcg_gen_neg_reg tcg_gen_neg_i64 85eaa3783bSRichard Henderson #define tcg_gen_subfi_reg tcg_gen_subfi_i64 86eaa3783bSRichard Henderson #define tcg_gen_subi_reg tcg_gen_subi_i64 87eaa3783bSRichard Henderson #define tcg_gen_and_reg tcg_gen_and_i64 88eaa3783bSRichard Henderson #define tcg_gen_andi_reg tcg_gen_andi_i64 89eaa3783bSRichard Henderson #define tcg_gen_or_reg tcg_gen_or_i64 90eaa3783bSRichard Henderson #define tcg_gen_ori_reg tcg_gen_ori_i64 91eaa3783bSRichard Henderson #define tcg_gen_xor_reg tcg_gen_xor_i64 92eaa3783bSRichard Henderson #define tcg_gen_xori_reg tcg_gen_xori_i64 93eaa3783bSRichard Henderson #define tcg_gen_not_reg tcg_gen_not_i64 94eaa3783bSRichard Henderson #define tcg_gen_shl_reg tcg_gen_shl_i64 95eaa3783bSRichard Henderson #define tcg_gen_shli_reg tcg_gen_shli_i64 96eaa3783bSRichard Henderson #define tcg_gen_shr_reg tcg_gen_shr_i64 97eaa3783bSRichard Henderson #define tcg_gen_shri_reg tcg_gen_shri_i64 98eaa3783bSRichard Henderson #define tcg_gen_sar_reg tcg_gen_sar_i64 99eaa3783bSRichard Henderson #define tcg_gen_sari_reg tcg_gen_sari_i64 100eaa3783bSRichard Henderson #define tcg_gen_brcond_reg tcg_gen_brcond_i64 101eaa3783bSRichard Henderson #define tcg_gen_brcondi_reg tcg_gen_brcondi_i64 102eaa3783bSRichard Henderson #define tcg_gen_setcond_reg tcg_gen_setcond_i64 103eaa3783bSRichard Henderson #define tcg_gen_setcondi_reg tcg_gen_setcondi_i64 104eaa3783bSRichard Henderson #define tcg_gen_mul_reg tcg_gen_mul_i64 105eaa3783bSRichard Henderson #define tcg_gen_muli_reg tcg_gen_muli_i64 106eaa3783bSRichard Henderson #define tcg_gen_div_reg tcg_gen_div_i64 107eaa3783bSRichard Henderson #define tcg_gen_rem_reg tcg_gen_rem_i64 108eaa3783bSRichard Henderson #define tcg_gen_divu_reg tcg_gen_divu_i64 109eaa3783bSRichard Henderson #define tcg_gen_remu_reg tcg_gen_remu_i64 110eaa3783bSRichard Henderson #define tcg_gen_discard_reg tcg_gen_discard_i64 111eaa3783bSRichard Henderson #define tcg_gen_trunc_reg_i32 tcg_gen_extrl_i64_i32 112eaa3783bSRichard Henderson #define tcg_gen_trunc_i64_reg tcg_gen_mov_i64 113eaa3783bSRichard Henderson #define tcg_gen_extu_i32_reg tcg_gen_extu_i32_i64 114eaa3783bSRichard Henderson #define tcg_gen_ext_i32_reg tcg_gen_ext_i32_i64 115eaa3783bSRichard Henderson #define tcg_gen_extu_reg_i64 tcg_gen_mov_i64 116eaa3783bSRichard Henderson #define tcg_gen_ext_reg_i64 tcg_gen_mov_i64 117eaa3783bSRichard Henderson #define tcg_gen_ext8u_reg tcg_gen_ext8u_i64 118eaa3783bSRichard Henderson #define tcg_gen_ext8s_reg tcg_gen_ext8s_i64 119eaa3783bSRichard Henderson #define tcg_gen_ext16u_reg tcg_gen_ext16u_i64 120eaa3783bSRichard Henderson #define tcg_gen_ext16s_reg tcg_gen_ext16s_i64 121eaa3783bSRichard Henderson #define tcg_gen_ext32u_reg tcg_gen_ext32u_i64 122eaa3783bSRichard Henderson #define tcg_gen_ext32s_reg tcg_gen_ext32s_i64 123eaa3783bSRichard Henderson #define tcg_gen_bswap16_reg tcg_gen_bswap16_i64 124eaa3783bSRichard Henderson #define tcg_gen_bswap32_reg tcg_gen_bswap32_i64 125eaa3783bSRichard Henderson #define tcg_gen_bswap64_reg tcg_gen_bswap64_i64 126eaa3783bSRichard Henderson #define tcg_gen_concat_reg_i64 tcg_gen_concat32_i64 127eaa3783bSRichard Henderson #define tcg_gen_andc_reg tcg_gen_andc_i64 128eaa3783bSRichard Henderson #define tcg_gen_eqv_reg tcg_gen_eqv_i64 129eaa3783bSRichard Henderson #define tcg_gen_nand_reg tcg_gen_nand_i64 130eaa3783bSRichard Henderson #define tcg_gen_nor_reg tcg_gen_nor_i64 131eaa3783bSRichard Henderson #define tcg_gen_orc_reg tcg_gen_orc_i64 132eaa3783bSRichard Henderson #define tcg_gen_clz_reg tcg_gen_clz_i64 133eaa3783bSRichard Henderson #define tcg_gen_ctz_reg tcg_gen_ctz_i64 134eaa3783bSRichard Henderson #define tcg_gen_clzi_reg tcg_gen_clzi_i64 135eaa3783bSRichard Henderson #define tcg_gen_ctzi_reg tcg_gen_ctzi_i64 136eaa3783bSRichard Henderson #define tcg_gen_clrsb_reg tcg_gen_clrsb_i64 137eaa3783bSRichard Henderson #define tcg_gen_ctpop_reg tcg_gen_ctpop_i64 138eaa3783bSRichard Henderson #define tcg_gen_rotl_reg tcg_gen_rotl_i64 139eaa3783bSRichard Henderson #define tcg_gen_rotli_reg tcg_gen_rotli_i64 140eaa3783bSRichard Henderson #define tcg_gen_rotr_reg tcg_gen_rotr_i64 141eaa3783bSRichard Henderson #define tcg_gen_rotri_reg tcg_gen_rotri_i64 142eaa3783bSRichard Henderson #define tcg_gen_deposit_reg tcg_gen_deposit_i64 143eaa3783bSRichard Henderson #define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i64 144eaa3783bSRichard Henderson #define tcg_gen_extract_reg tcg_gen_extract_i64 145eaa3783bSRichard Henderson #define tcg_gen_sextract_reg tcg_gen_sextract_i64 146eaa3783bSRichard Henderson #define tcg_const_reg tcg_const_i64 147eaa3783bSRichard Henderson #define tcg_const_local_reg tcg_const_local_i64 148eaa3783bSRichard Henderson #define tcg_gen_movcond_reg tcg_gen_movcond_i64 149eaa3783bSRichard Henderson #define tcg_gen_add2_reg tcg_gen_add2_i64 150eaa3783bSRichard Henderson #define tcg_gen_sub2_reg tcg_gen_sub2_i64 151eaa3783bSRichard Henderson #define tcg_gen_qemu_ld_reg tcg_gen_qemu_ld_i64 152eaa3783bSRichard Henderson #define tcg_gen_qemu_st_reg tcg_gen_qemu_st_i64 153eaa3783bSRichard Henderson #define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i64 1545bfa8034SRichard Henderson #define tcg_gen_trunc_reg_ptr tcg_gen_trunc_i64_ptr 155eaa3783bSRichard Henderson #else 156eaa3783bSRichard Henderson #define TCGv_reg TCGv_i32 157eaa3783bSRichard Henderson #define tcg_temp_new tcg_temp_new_i32 158eaa3783bSRichard Henderson #define tcg_global_reg_new tcg_global_reg_new_i32 159eaa3783bSRichard Henderson #define tcg_global_mem_new tcg_global_mem_new_i32 160eaa3783bSRichard Henderson #define tcg_temp_local_new tcg_temp_local_new_i32 161eaa3783bSRichard Henderson #define tcg_temp_free tcg_temp_free_i32 162eaa3783bSRichard Henderson 163eaa3783bSRichard Henderson #define tcg_gen_movi_reg tcg_gen_movi_i32 164eaa3783bSRichard Henderson #define tcg_gen_mov_reg tcg_gen_mov_i32 165eaa3783bSRichard Henderson #define tcg_gen_ld8u_reg tcg_gen_ld8u_i32 166eaa3783bSRichard Henderson #define tcg_gen_ld8s_reg tcg_gen_ld8s_i32 167eaa3783bSRichard Henderson #define tcg_gen_ld16u_reg tcg_gen_ld16u_i32 168eaa3783bSRichard Henderson #define tcg_gen_ld16s_reg tcg_gen_ld16s_i32 169eaa3783bSRichard Henderson #define tcg_gen_ld32u_reg tcg_gen_ld_i32 170eaa3783bSRichard Henderson #define tcg_gen_ld32s_reg tcg_gen_ld_i32 171eaa3783bSRichard Henderson #define tcg_gen_ld_reg tcg_gen_ld_i32 172eaa3783bSRichard Henderson #define tcg_gen_st8_reg tcg_gen_st8_i32 173eaa3783bSRichard Henderson #define tcg_gen_st16_reg tcg_gen_st16_i32 174eaa3783bSRichard Henderson #define tcg_gen_st32_reg tcg_gen_st32_i32 175eaa3783bSRichard Henderson #define tcg_gen_st_reg tcg_gen_st_i32 176eaa3783bSRichard Henderson #define tcg_gen_add_reg tcg_gen_add_i32 177eaa3783bSRichard Henderson #define tcg_gen_addi_reg tcg_gen_addi_i32 178eaa3783bSRichard Henderson #define tcg_gen_sub_reg tcg_gen_sub_i32 179eaa3783bSRichard Henderson #define tcg_gen_neg_reg tcg_gen_neg_i32 180eaa3783bSRichard Henderson #define tcg_gen_subfi_reg tcg_gen_subfi_i32 181eaa3783bSRichard Henderson #define tcg_gen_subi_reg tcg_gen_subi_i32 182eaa3783bSRichard Henderson #define tcg_gen_and_reg tcg_gen_and_i32 183eaa3783bSRichard Henderson #define tcg_gen_andi_reg tcg_gen_andi_i32 184eaa3783bSRichard Henderson #define tcg_gen_or_reg tcg_gen_or_i32 185eaa3783bSRichard Henderson #define tcg_gen_ori_reg tcg_gen_ori_i32 186eaa3783bSRichard Henderson #define tcg_gen_xor_reg tcg_gen_xor_i32 187eaa3783bSRichard Henderson #define tcg_gen_xori_reg tcg_gen_xori_i32 188eaa3783bSRichard Henderson #define tcg_gen_not_reg tcg_gen_not_i32 189eaa3783bSRichard Henderson #define tcg_gen_shl_reg tcg_gen_shl_i32 190eaa3783bSRichard Henderson #define tcg_gen_shli_reg tcg_gen_shli_i32 191eaa3783bSRichard Henderson #define tcg_gen_shr_reg tcg_gen_shr_i32 192eaa3783bSRichard Henderson #define tcg_gen_shri_reg tcg_gen_shri_i32 193eaa3783bSRichard Henderson #define tcg_gen_sar_reg tcg_gen_sar_i32 194eaa3783bSRichard Henderson #define tcg_gen_sari_reg tcg_gen_sari_i32 195eaa3783bSRichard Henderson #define tcg_gen_brcond_reg tcg_gen_brcond_i32 196eaa3783bSRichard Henderson #define tcg_gen_brcondi_reg tcg_gen_brcondi_i32 197eaa3783bSRichard Henderson #define tcg_gen_setcond_reg tcg_gen_setcond_i32 198eaa3783bSRichard Henderson #define tcg_gen_setcondi_reg tcg_gen_setcondi_i32 199eaa3783bSRichard Henderson #define tcg_gen_mul_reg tcg_gen_mul_i32 200eaa3783bSRichard Henderson #define tcg_gen_muli_reg tcg_gen_muli_i32 201eaa3783bSRichard Henderson #define tcg_gen_div_reg tcg_gen_div_i32 202eaa3783bSRichard Henderson #define tcg_gen_rem_reg tcg_gen_rem_i32 203eaa3783bSRichard Henderson #define tcg_gen_divu_reg tcg_gen_divu_i32 204eaa3783bSRichard Henderson #define tcg_gen_remu_reg tcg_gen_remu_i32 205eaa3783bSRichard Henderson #define tcg_gen_discard_reg tcg_gen_discard_i32 206eaa3783bSRichard Henderson #define tcg_gen_trunc_reg_i32 tcg_gen_mov_i32 207eaa3783bSRichard Henderson #define tcg_gen_trunc_i64_reg tcg_gen_extrl_i64_i32 208eaa3783bSRichard Henderson #define tcg_gen_extu_i32_reg tcg_gen_mov_i32 209eaa3783bSRichard Henderson #define tcg_gen_ext_i32_reg tcg_gen_mov_i32 210eaa3783bSRichard Henderson #define tcg_gen_extu_reg_i64 tcg_gen_extu_i32_i64 211eaa3783bSRichard Henderson #define tcg_gen_ext_reg_i64 tcg_gen_ext_i32_i64 212eaa3783bSRichard Henderson #define tcg_gen_ext8u_reg tcg_gen_ext8u_i32 213eaa3783bSRichard Henderson #define tcg_gen_ext8s_reg tcg_gen_ext8s_i32 214eaa3783bSRichard Henderson #define tcg_gen_ext16u_reg tcg_gen_ext16u_i32 215eaa3783bSRichard Henderson #define tcg_gen_ext16s_reg tcg_gen_ext16s_i32 216eaa3783bSRichard Henderson #define tcg_gen_ext32u_reg tcg_gen_mov_i32 217eaa3783bSRichard Henderson #define tcg_gen_ext32s_reg tcg_gen_mov_i32 218eaa3783bSRichard Henderson #define tcg_gen_bswap16_reg tcg_gen_bswap16_i32 219eaa3783bSRichard Henderson #define tcg_gen_bswap32_reg tcg_gen_bswap32_i32 220eaa3783bSRichard Henderson #define tcg_gen_concat_reg_i64 tcg_gen_concat_i32_i64 221eaa3783bSRichard Henderson #define tcg_gen_andc_reg tcg_gen_andc_i32 222eaa3783bSRichard Henderson #define tcg_gen_eqv_reg tcg_gen_eqv_i32 223eaa3783bSRichard Henderson #define tcg_gen_nand_reg tcg_gen_nand_i32 224eaa3783bSRichard Henderson #define tcg_gen_nor_reg tcg_gen_nor_i32 225eaa3783bSRichard Henderson #define tcg_gen_orc_reg tcg_gen_orc_i32 226eaa3783bSRichard Henderson #define tcg_gen_clz_reg tcg_gen_clz_i32 227eaa3783bSRichard Henderson #define tcg_gen_ctz_reg tcg_gen_ctz_i32 228eaa3783bSRichard Henderson #define tcg_gen_clzi_reg tcg_gen_clzi_i32 229eaa3783bSRichard Henderson #define tcg_gen_ctzi_reg tcg_gen_ctzi_i32 230eaa3783bSRichard Henderson #define tcg_gen_clrsb_reg tcg_gen_clrsb_i32 231eaa3783bSRichard Henderson #define tcg_gen_ctpop_reg tcg_gen_ctpop_i32 232eaa3783bSRichard Henderson #define tcg_gen_rotl_reg tcg_gen_rotl_i32 233eaa3783bSRichard Henderson #define tcg_gen_rotli_reg tcg_gen_rotli_i32 234eaa3783bSRichard Henderson #define tcg_gen_rotr_reg tcg_gen_rotr_i32 235eaa3783bSRichard Henderson #define tcg_gen_rotri_reg tcg_gen_rotri_i32 236eaa3783bSRichard Henderson #define tcg_gen_deposit_reg tcg_gen_deposit_i32 237eaa3783bSRichard Henderson #define tcg_gen_deposit_z_reg tcg_gen_deposit_z_i32 238eaa3783bSRichard Henderson #define tcg_gen_extract_reg tcg_gen_extract_i32 239eaa3783bSRichard Henderson #define tcg_gen_sextract_reg tcg_gen_sextract_i32 240eaa3783bSRichard Henderson #define tcg_const_reg tcg_const_i32 241eaa3783bSRichard Henderson #define tcg_const_local_reg tcg_const_local_i32 242eaa3783bSRichard Henderson #define tcg_gen_movcond_reg tcg_gen_movcond_i32 243eaa3783bSRichard Henderson #define tcg_gen_add2_reg tcg_gen_add2_i32 244eaa3783bSRichard Henderson #define tcg_gen_sub2_reg tcg_gen_sub2_i32 245eaa3783bSRichard Henderson #define tcg_gen_qemu_ld_reg tcg_gen_qemu_ld_i32 246eaa3783bSRichard Henderson #define tcg_gen_qemu_st_reg tcg_gen_qemu_st_i32 247eaa3783bSRichard Henderson #define tcg_gen_atomic_xchg_reg tcg_gen_atomic_xchg_i32 2485bfa8034SRichard Henderson #define tcg_gen_trunc_reg_ptr tcg_gen_ext_i32_ptr 249eaa3783bSRichard Henderson #endif /* TARGET_REGISTER_BITS */ 250eaa3783bSRichard Henderson 25161766fe9SRichard Henderson typedef struct DisasCond { 25261766fe9SRichard Henderson TCGCond c; 253eaa3783bSRichard Henderson TCGv_reg a0, a1; 25461766fe9SRichard Henderson bool a0_is_n; 25561766fe9SRichard Henderson bool a1_is_0; 25661766fe9SRichard Henderson } DisasCond; 25761766fe9SRichard Henderson 25861766fe9SRichard Henderson typedef struct DisasContext { 259d01a3625SRichard Henderson DisasContextBase base; 26061766fe9SRichard Henderson CPUState *cs; 26161766fe9SRichard Henderson 262eaa3783bSRichard Henderson target_ureg iaoq_f; 263eaa3783bSRichard Henderson target_ureg iaoq_b; 264eaa3783bSRichard Henderson target_ureg iaoq_n; 265eaa3783bSRichard Henderson TCGv_reg iaoq_n_var; 26661766fe9SRichard Henderson 26786f8d05fSRichard Henderson int ntempr, ntempl; 2685eecd37aSRichard Henderson TCGv_reg tempr[8]; 26986f8d05fSRichard Henderson TCGv_tl templ[4]; 27061766fe9SRichard Henderson 27161766fe9SRichard Henderson DisasCond null_cond; 27261766fe9SRichard Henderson TCGLabel *null_lab; 27361766fe9SRichard Henderson 2741a19da0dSRichard Henderson uint32_t insn; 275494737b7SRichard Henderson uint32_t tb_flags; 2763d68ee7bSRichard Henderson int mmu_idx; 2773d68ee7bSRichard Henderson int privilege; 27861766fe9SRichard Henderson bool psw_n_nonzero; 27961766fe9SRichard Henderson } DisasContext; 28061766fe9SRichard Henderson 281e36f27efSRichard Henderson /* Note that ssm/rsm instructions number PSW_W and PSW_E differently. */ 282e36f27efSRichard Henderson static int expand_sm_imm(int val) 283e36f27efSRichard Henderson { 284e36f27efSRichard Henderson if (val & PSW_SM_E) { 285e36f27efSRichard Henderson val = (val & ~PSW_SM_E) | PSW_E; 286e36f27efSRichard Henderson } 287e36f27efSRichard Henderson if (val & PSW_SM_W) { 288e36f27efSRichard Henderson val = (val & ~PSW_SM_W) | PSW_W; 289e36f27efSRichard Henderson } 290e36f27efSRichard Henderson return val; 291e36f27efSRichard Henderson } 292e36f27efSRichard Henderson 293deee69a1SRichard Henderson /* Inverted space register indicates 0 means sr0 not inferred from base. */ 294deee69a1SRichard Henderson static int expand_sr3x(int val) 295deee69a1SRichard Henderson { 296deee69a1SRichard Henderson return ~val; 297deee69a1SRichard Henderson } 298deee69a1SRichard Henderson 2991cd012a5SRichard Henderson /* Convert the M:A bits within a memory insn to the tri-state value 3001cd012a5SRichard Henderson we use for the final M. */ 3011cd012a5SRichard Henderson static int ma_to_m(int val) 3021cd012a5SRichard Henderson { 3031cd012a5SRichard Henderson return val & 2 ? (val & 1 ? -1 : 1) : 0; 3041cd012a5SRichard Henderson } 3051cd012a5SRichard Henderson 30601afb7beSRichard Henderson /* Used for branch targets. */ 30701afb7beSRichard Henderson static int expand_shl2(int val) 30801afb7beSRichard Henderson { 30901afb7beSRichard Henderson return val << 2; 31001afb7beSRichard Henderson } 31101afb7beSRichard Henderson 31201afb7beSRichard Henderson 31340f9f908SRichard Henderson /* Include the auto-generated decoder. */ 31440f9f908SRichard Henderson #include "decode.inc.c" 31540f9f908SRichard Henderson 31661766fe9SRichard Henderson /* We are not using a goto_tb (for whatever reason), but have updated 31761766fe9SRichard Henderson the iaq (for whatever reason), so don't do it again on exit. */ 318869051eaSRichard Henderson #define DISAS_IAQ_N_UPDATED DISAS_TARGET_0 31961766fe9SRichard Henderson 32061766fe9SRichard Henderson /* We are exiting the TB, but have neither emitted a goto_tb, nor 32161766fe9SRichard Henderson updated the iaq for the next instruction to be executed. */ 322869051eaSRichard Henderson #define DISAS_IAQ_N_STALE DISAS_TARGET_1 32361766fe9SRichard Henderson 324e1b5a5edSRichard Henderson /* Similarly, but we want to return to the main loop immediately 325e1b5a5edSRichard Henderson to recognize unmasked interrupts. */ 326e1b5a5edSRichard Henderson #define DISAS_IAQ_N_STALE_EXIT DISAS_TARGET_2 327e1b5a5edSRichard Henderson 32861766fe9SRichard Henderson typedef struct DisasInsn { 32961766fe9SRichard Henderson uint32_t insn, mask; 33031234768SRichard Henderson bool (*trans)(DisasContext *ctx, uint32_t insn, 33161766fe9SRichard Henderson const struct DisasInsn *f); 332b2167459SRichard Henderson union { 333eaa3783bSRichard Henderson void (*ttt)(TCGv_reg, TCGv_reg, TCGv_reg); 334eff235ebSPaolo Bonzini void (*weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32); 335eff235ebSPaolo Bonzini void (*dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64); 336eff235ebSPaolo Bonzini void (*wew)(TCGv_i32, TCGv_env, TCGv_i32); 337eff235ebSPaolo Bonzini void (*ded)(TCGv_i64, TCGv_env, TCGv_i64); 338eff235ebSPaolo Bonzini void (*wed)(TCGv_i32, TCGv_env, TCGv_i64); 339eff235ebSPaolo Bonzini void (*dew)(TCGv_i64, TCGv_env, TCGv_i32); 340eff235ebSPaolo Bonzini } f; 34161766fe9SRichard Henderson } DisasInsn; 34261766fe9SRichard Henderson 34361766fe9SRichard Henderson /* global register indexes */ 344eaa3783bSRichard Henderson static TCGv_reg cpu_gr[32]; 34533423472SRichard Henderson static TCGv_i64 cpu_sr[4]; 346494737b7SRichard Henderson static TCGv_i64 cpu_srH; 347eaa3783bSRichard Henderson static TCGv_reg cpu_iaoq_f; 348eaa3783bSRichard Henderson static TCGv_reg cpu_iaoq_b; 349c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_f; 350c301f34eSRichard Henderson static TCGv_i64 cpu_iasq_b; 351eaa3783bSRichard Henderson static TCGv_reg cpu_sar; 352eaa3783bSRichard Henderson static TCGv_reg cpu_psw_n; 353eaa3783bSRichard Henderson static TCGv_reg cpu_psw_v; 354eaa3783bSRichard Henderson static TCGv_reg cpu_psw_cb; 355eaa3783bSRichard Henderson static TCGv_reg cpu_psw_cb_msb; 35661766fe9SRichard Henderson 35761766fe9SRichard Henderson #include "exec/gen-icount.h" 35861766fe9SRichard Henderson 35961766fe9SRichard Henderson void hppa_translate_init(void) 36061766fe9SRichard Henderson { 36161766fe9SRichard Henderson #define DEF_VAR(V) { &cpu_##V, #V, offsetof(CPUHPPAState, V) } 36261766fe9SRichard Henderson 363eaa3783bSRichard Henderson typedef struct { TCGv_reg *var; const char *name; int ofs; } GlobalVar; 36461766fe9SRichard Henderson static const GlobalVar vars[] = { 36535136a77SRichard Henderson { &cpu_sar, "sar", offsetof(CPUHPPAState, cr[CR_SAR]) }, 36661766fe9SRichard Henderson DEF_VAR(psw_n), 36761766fe9SRichard Henderson DEF_VAR(psw_v), 36861766fe9SRichard Henderson DEF_VAR(psw_cb), 36961766fe9SRichard Henderson DEF_VAR(psw_cb_msb), 37061766fe9SRichard Henderson DEF_VAR(iaoq_f), 37161766fe9SRichard Henderson DEF_VAR(iaoq_b), 37261766fe9SRichard Henderson }; 37361766fe9SRichard Henderson 37461766fe9SRichard Henderson #undef DEF_VAR 37561766fe9SRichard Henderson 37661766fe9SRichard Henderson /* Use the symbolic register names that match the disassembler. */ 37761766fe9SRichard Henderson static const char gr_names[32][4] = { 37861766fe9SRichard Henderson "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 37961766fe9SRichard Henderson "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 38061766fe9SRichard Henderson "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 38161766fe9SRichard Henderson "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 38261766fe9SRichard Henderson }; 38333423472SRichard Henderson /* SR[4-7] are not global registers so that we can index them. */ 384494737b7SRichard Henderson static const char sr_names[5][4] = { 385494737b7SRichard Henderson "sr0", "sr1", "sr2", "sr3", "srH" 38633423472SRichard Henderson }; 38761766fe9SRichard Henderson 38861766fe9SRichard Henderson int i; 38961766fe9SRichard Henderson 390f764718dSRichard Henderson cpu_gr[0] = NULL; 39161766fe9SRichard Henderson for (i = 1; i < 32; i++) { 39261766fe9SRichard Henderson cpu_gr[i] = tcg_global_mem_new(cpu_env, 39361766fe9SRichard Henderson offsetof(CPUHPPAState, gr[i]), 39461766fe9SRichard Henderson gr_names[i]); 39561766fe9SRichard Henderson } 39633423472SRichard Henderson for (i = 0; i < 4; i++) { 39733423472SRichard Henderson cpu_sr[i] = tcg_global_mem_new_i64(cpu_env, 39833423472SRichard Henderson offsetof(CPUHPPAState, sr[i]), 39933423472SRichard Henderson sr_names[i]); 40033423472SRichard Henderson } 401494737b7SRichard Henderson cpu_srH = tcg_global_mem_new_i64(cpu_env, 402494737b7SRichard Henderson offsetof(CPUHPPAState, sr[4]), 403494737b7SRichard Henderson sr_names[4]); 40461766fe9SRichard Henderson 40561766fe9SRichard Henderson for (i = 0; i < ARRAY_SIZE(vars); ++i) { 40661766fe9SRichard Henderson const GlobalVar *v = &vars[i]; 40761766fe9SRichard Henderson *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name); 40861766fe9SRichard Henderson } 409c301f34eSRichard Henderson 410c301f34eSRichard Henderson cpu_iasq_f = tcg_global_mem_new_i64(cpu_env, 411c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_f), 412c301f34eSRichard Henderson "iasq_f"); 413c301f34eSRichard Henderson cpu_iasq_b = tcg_global_mem_new_i64(cpu_env, 414c301f34eSRichard Henderson offsetof(CPUHPPAState, iasq_b), 415c301f34eSRichard Henderson "iasq_b"); 41661766fe9SRichard Henderson } 41761766fe9SRichard Henderson 418129e9cc3SRichard Henderson static DisasCond cond_make_f(void) 419129e9cc3SRichard Henderson { 420f764718dSRichard Henderson return (DisasCond){ 421f764718dSRichard Henderson .c = TCG_COND_NEVER, 422f764718dSRichard Henderson .a0 = NULL, 423f764718dSRichard Henderson .a1 = NULL, 424f764718dSRichard Henderson }; 425129e9cc3SRichard Henderson } 426129e9cc3SRichard Henderson 427129e9cc3SRichard Henderson static DisasCond cond_make_n(void) 428129e9cc3SRichard Henderson { 429f764718dSRichard Henderson return (DisasCond){ 430f764718dSRichard Henderson .c = TCG_COND_NE, 431f764718dSRichard Henderson .a0 = cpu_psw_n, 432f764718dSRichard Henderson .a0_is_n = true, 433f764718dSRichard Henderson .a1 = NULL, 434f764718dSRichard Henderson .a1_is_0 = true 435f764718dSRichard Henderson }; 436129e9cc3SRichard Henderson } 437129e9cc3SRichard Henderson 438eaa3783bSRichard Henderson static DisasCond cond_make_0(TCGCond c, TCGv_reg a0) 439129e9cc3SRichard Henderson { 440f764718dSRichard Henderson DisasCond r = { .c = c, .a1 = NULL, .a1_is_0 = true }; 441129e9cc3SRichard Henderson 442129e9cc3SRichard Henderson assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 443129e9cc3SRichard Henderson r.a0 = tcg_temp_new(); 444eaa3783bSRichard Henderson tcg_gen_mov_reg(r.a0, a0); 445129e9cc3SRichard Henderson 446129e9cc3SRichard Henderson return r; 447129e9cc3SRichard Henderson } 448129e9cc3SRichard Henderson 449eaa3783bSRichard Henderson static DisasCond cond_make(TCGCond c, TCGv_reg a0, TCGv_reg a1) 450129e9cc3SRichard Henderson { 451129e9cc3SRichard Henderson DisasCond r = { .c = c }; 452129e9cc3SRichard Henderson 453129e9cc3SRichard Henderson assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); 454129e9cc3SRichard Henderson r.a0 = tcg_temp_new(); 455eaa3783bSRichard Henderson tcg_gen_mov_reg(r.a0, a0); 456129e9cc3SRichard Henderson r.a1 = tcg_temp_new(); 457eaa3783bSRichard Henderson tcg_gen_mov_reg(r.a1, a1); 458129e9cc3SRichard Henderson 459129e9cc3SRichard Henderson return r; 460129e9cc3SRichard Henderson } 461129e9cc3SRichard Henderson 462129e9cc3SRichard Henderson static void cond_prep(DisasCond *cond) 463129e9cc3SRichard Henderson { 464129e9cc3SRichard Henderson if (cond->a1_is_0) { 465129e9cc3SRichard Henderson cond->a1_is_0 = false; 466eaa3783bSRichard Henderson cond->a1 = tcg_const_reg(0); 467129e9cc3SRichard Henderson } 468129e9cc3SRichard Henderson } 469129e9cc3SRichard Henderson 470129e9cc3SRichard Henderson static void cond_free(DisasCond *cond) 471129e9cc3SRichard Henderson { 472129e9cc3SRichard Henderson switch (cond->c) { 473129e9cc3SRichard Henderson default: 474129e9cc3SRichard Henderson if (!cond->a0_is_n) { 475129e9cc3SRichard Henderson tcg_temp_free(cond->a0); 476129e9cc3SRichard Henderson } 477129e9cc3SRichard Henderson if (!cond->a1_is_0) { 478129e9cc3SRichard Henderson tcg_temp_free(cond->a1); 479129e9cc3SRichard Henderson } 480129e9cc3SRichard Henderson cond->a0_is_n = false; 481129e9cc3SRichard Henderson cond->a1_is_0 = false; 482f764718dSRichard Henderson cond->a0 = NULL; 483f764718dSRichard Henderson cond->a1 = NULL; 484129e9cc3SRichard Henderson /* fallthru */ 485129e9cc3SRichard Henderson case TCG_COND_ALWAYS: 486129e9cc3SRichard Henderson cond->c = TCG_COND_NEVER; 487129e9cc3SRichard Henderson break; 488129e9cc3SRichard Henderson case TCG_COND_NEVER: 489129e9cc3SRichard Henderson break; 490129e9cc3SRichard Henderson } 491129e9cc3SRichard Henderson } 492129e9cc3SRichard Henderson 493eaa3783bSRichard Henderson static TCGv_reg get_temp(DisasContext *ctx) 49461766fe9SRichard Henderson { 49586f8d05fSRichard Henderson unsigned i = ctx->ntempr++; 49686f8d05fSRichard Henderson g_assert(i < ARRAY_SIZE(ctx->tempr)); 49786f8d05fSRichard Henderson return ctx->tempr[i] = tcg_temp_new(); 49861766fe9SRichard Henderson } 49961766fe9SRichard Henderson 50086f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 50186f8d05fSRichard Henderson static TCGv_tl get_temp_tl(DisasContext *ctx) 50286f8d05fSRichard Henderson { 50386f8d05fSRichard Henderson unsigned i = ctx->ntempl++; 50486f8d05fSRichard Henderson g_assert(i < ARRAY_SIZE(ctx->templ)); 50586f8d05fSRichard Henderson return ctx->templ[i] = tcg_temp_new_tl(); 50686f8d05fSRichard Henderson } 50786f8d05fSRichard Henderson #endif 50886f8d05fSRichard Henderson 509eaa3783bSRichard Henderson static TCGv_reg load_const(DisasContext *ctx, target_sreg v) 51061766fe9SRichard Henderson { 511eaa3783bSRichard Henderson TCGv_reg t = get_temp(ctx); 512eaa3783bSRichard Henderson tcg_gen_movi_reg(t, v); 51361766fe9SRichard Henderson return t; 51461766fe9SRichard Henderson } 51561766fe9SRichard Henderson 516eaa3783bSRichard Henderson static TCGv_reg load_gpr(DisasContext *ctx, unsigned reg) 51761766fe9SRichard Henderson { 51861766fe9SRichard Henderson if (reg == 0) { 519eaa3783bSRichard Henderson TCGv_reg t = get_temp(ctx); 520eaa3783bSRichard Henderson tcg_gen_movi_reg(t, 0); 52161766fe9SRichard Henderson return t; 52261766fe9SRichard Henderson } else { 52361766fe9SRichard Henderson return cpu_gr[reg]; 52461766fe9SRichard Henderson } 52561766fe9SRichard Henderson } 52661766fe9SRichard Henderson 527eaa3783bSRichard Henderson static TCGv_reg dest_gpr(DisasContext *ctx, unsigned reg) 52861766fe9SRichard Henderson { 529129e9cc3SRichard Henderson if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) { 53061766fe9SRichard Henderson return get_temp(ctx); 53161766fe9SRichard Henderson } else { 53261766fe9SRichard Henderson return cpu_gr[reg]; 53361766fe9SRichard Henderson } 53461766fe9SRichard Henderson } 53561766fe9SRichard Henderson 536eaa3783bSRichard Henderson static void save_or_nullify(DisasContext *ctx, TCGv_reg dest, TCGv_reg t) 537129e9cc3SRichard Henderson { 538129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 539129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 540eaa3783bSRichard Henderson tcg_gen_movcond_reg(ctx->null_cond.c, dest, ctx->null_cond.a0, 541129e9cc3SRichard Henderson ctx->null_cond.a1, dest, t); 542129e9cc3SRichard Henderson } else { 543eaa3783bSRichard Henderson tcg_gen_mov_reg(dest, t); 544129e9cc3SRichard Henderson } 545129e9cc3SRichard Henderson } 546129e9cc3SRichard Henderson 547eaa3783bSRichard Henderson static void save_gpr(DisasContext *ctx, unsigned reg, TCGv_reg t) 548129e9cc3SRichard Henderson { 549129e9cc3SRichard Henderson if (reg != 0) { 550129e9cc3SRichard Henderson save_or_nullify(ctx, cpu_gr[reg], t); 551129e9cc3SRichard Henderson } 552129e9cc3SRichard Henderson } 553129e9cc3SRichard Henderson 55496d6407fSRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 55596d6407fSRichard Henderson # define HI_OFS 0 55696d6407fSRichard Henderson # define LO_OFS 4 55796d6407fSRichard Henderson #else 55896d6407fSRichard Henderson # define HI_OFS 4 55996d6407fSRichard Henderson # define LO_OFS 0 56096d6407fSRichard Henderson #endif 56196d6407fSRichard Henderson 56296d6407fSRichard Henderson static TCGv_i32 load_frw_i32(unsigned rt) 56396d6407fSRichard Henderson { 56496d6407fSRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 56596d6407fSRichard Henderson tcg_gen_ld_i32(ret, cpu_env, 56696d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 56796d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 56896d6407fSRichard Henderson return ret; 56996d6407fSRichard Henderson } 57096d6407fSRichard Henderson 571ebe9383cSRichard Henderson static TCGv_i32 load_frw0_i32(unsigned rt) 572ebe9383cSRichard Henderson { 573ebe9383cSRichard Henderson if (rt == 0) { 574ebe9383cSRichard Henderson return tcg_const_i32(0); 575ebe9383cSRichard Henderson } else { 576ebe9383cSRichard Henderson return load_frw_i32(rt); 577ebe9383cSRichard Henderson } 578ebe9383cSRichard Henderson } 579ebe9383cSRichard Henderson 580ebe9383cSRichard Henderson static TCGv_i64 load_frw0_i64(unsigned rt) 581ebe9383cSRichard Henderson { 582ebe9383cSRichard Henderson if (rt == 0) { 583ebe9383cSRichard Henderson return tcg_const_i64(0); 584ebe9383cSRichard Henderson } else { 585ebe9383cSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 586ebe9383cSRichard Henderson tcg_gen_ld32u_i64(ret, cpu_env, 587ebe9383cSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 588ebe9383cSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 589ebe9383cSRichard Henderson return ret; 590ebe9383cSRichard Henderson } 591ebe9383cSRichard Henderson } 592ebe9383cSRichard Henderson 59396d6407fSRichard Henderson static void save_frw_i32(unsigned rt, TCGv_i32 val) 59496d6407fSRichard Henderson { 59596d6407fSRichard Henderson tcg_gen_st_i32(val, cpu_env, 59696d6407fSRichard Henderson offsetof(CPUHPPAState, fr[rt & 31]) 59796d6407fSRichard Henderson + (rt & 32 ? LO_OFS : HI_OFS)); 59896d6407fSRichard Henderson } 59996d6407fSRichard Henderson 60096d6407fSRichard Henderson #undef HI_OFS 60196d6407fSRichard Henderson #undef LO_OFS 60296d6407fSRichard Henderson 60396d6407fSRichard Henderson static TCGv_i64 load_frd(unsigned rt) 60496d6407fSRichard Henderson { 60596d6407fSRichard Henderson TCGv_i64 ret = tcg_temp_new_i64(); 60696d6407fSRichard Henderson tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt])); 60796d6407fSRichard Henderson return ret; 60896d6407fSRichard Henderson } 60996d6407fSRichard Henderson 610ebe9383cSRichard Henderson static TCGv_i64 load_frd0(unsigned rt) 611ebe9383cSRichard Henderson { 612ebe9383cSRichard Henderson if (rt == 0) { 613ebe9383cSRichard Henderson return tcg_const_i64(0); 614ebe9383cSRichard Henderson } else { 615ebe9383cSRichard Henderson return load_frd(rt); 616ebe9383cSRichard Henderson } 617ebe9383cSRichard Henderson } 618ebe9383cSRichard Henderson 61996d6407fSRichard Henderson static void save_frd(unsigned rt, TCGv_i64 val) 62096d6407fSRichard Henderson { 62196d6407fSRichard Henderson tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt])); 62296d6407fSRichard Henderson } 62396d6407fSRichard Henderson 62433423472SRichard Henderson static void load_spr(DisasContext *ctx, TCGv_i64 dest, unsigned reg) 62533423472SRichard Henderson { 62633423472SRichard Henderson #ifdef CONFIG_USER_ONLY 62733423472SRichard Henderson tcg_gen_movi_i64(dest, 0); 62833423472SRichard Henderson #else 62933423472SRichard Henderson if (reg < 4) { 63033423472SRichard Henderson tcg_gen_mov_i64(dest, cpu_sr[reg]); 631494737b7SRichard Henderson } else if (ctx->tb_flags & TB_FLAG_SR_SAME) { 632494737b7SRichard Henderson tcg_gen_mov_i64(dest, cpu_srH); 63333423472SRichard Henderson } else { 63433423472SRichard Henderson tcg_gen_ld_i64(dest, cpu_env, offsetof(CPUHPPAState, sr[reg])); 63533423472SRichard Henderson } 63633423472SRichard Henderson #endif 63733423472SRichard Henderson } 63833423472SRichard Henderson 639129e9cc3SRichard Henderson /* Skip over the implementation of an insn that has been nullified. 640129e9cc3SRichard Henderson Use this when the insn is too complex for a conditional move. */ 641129e9cc3SRichard Henderson static void nullify_over(DisasContext *ctx) 642129e9cc3SRichard Henderson { 643129e9cc3SRichard Henderson if (ctx->null_cond.c != TCG_COND_NEVER) { 644129e9cc3SRichard Henderson /* The always condition should have been handled in the main loop. */ 645129e9cc3SRichard Henderson assert(ctx->null_cond.c != TCG_COND_ALWAYS); 646129e9cc3SRichard Henderson 647129e9cc3SRichard Henderson ctx->null_lab = gen_new_label(); 648129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 649129e9cc3SRichard Henderson 650129e9cc3SRichard Henderson /* If we're using PSW[N], copy it to a temp because... */ 651129e9cc3SRichard Henderson if (ctx->null_cond.a0_is_n) { 652129e9cc3SRichard Henderson ctx->null_cond.a0_is_n = false; 653129e9cc3SRichard Henderson ctx->null_cond.a0 = tcg_temp_new(); 654eaa3783bSRichard Henderson tcg_gen_mov_reg(ctx->null_cond.a0, cpu_psw_n); 655129e9cc3SRichard Henderson } 656129e9cc3SRichard Henderson /* ... we clear it before branching over the implementation, 657129e9cc3SRichard Henderson so that (1) it's clear after nullifying this insn and 658129e9cc3SRichard Henderson (2) if this insn nullifies the next, PSW[N] is valid. */ 659129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 660129e9cc3SRichard Henderson ctx->psw_n_nonzero = false; 661eaa3783bSRichard Henderson tcg_gen_movi_reg(cpu_psw_n, 0); 662129e9cc3SRichard Henderson } 663129e9cc3SRichard Henderson 664eaa3783bSRichard Henderson tcg_gen_brcond_reg(ctx->null_cond.c, ctx->null_cond.a0, 665129e9cc3SRichard Henderson ctx->null_cond.a1, ctx->null_lab); 666129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 667129e9cc3SRichard Henderson } 668129e9cc3SRichard Henderson } 669129e9cc3SRichard Henderson 670129e9cc3SRichard Henderson /* Save the current nullification state to PSW[N]. */ 671129e9cc3SRichard Henderson static void nullify_save(DisasContext *ctx) 672129e9cc3SRichard Henderson { 673129e9cc3SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 674129e9cc3SRichard Henderson if (ctx->psw_n_nonzero) { 675eaa3783bSRichard Henderson tcg_gen_movi_reg(cpu_psw_n, 0); 676129e9cc3SRichard Henderson } 677129e9cc3SRichard Henderson return; 678129e9cc3SRichard Henderson } 679129e9cc3SRichard Henderson if (!ctx->null_cond.a0_is_n) { 680129e9cc3SRichard Henderson cond_prep(&ctx->null_cond); 681eaa3783bSRichard Henderson tcg_gen_setcond_reg(ctx->null_cond.c, cpu_psw_n, 682129e9cc3SRichard Henderson ctx->null_cond.a0, ctx->null_cond.a1); 683129e9cc3SRichard Henderson ctx->psw_n_nonzero = true; 684129e9cc3SRichard Henderson } 685129e9cc3SRichard Henderson cond_free(&ctx->null_cond); 686129e9cc3SRichard Henderson } 687129e9cc3SRichard Henderson 688129e9cc3SRichard Henderson /* Set a PSW[N] to X. The intention is that this is used immediately 689129e9cc3SRichard Henderson before a goto_tb/exit_tb, so that there is no fallthru path to other 690129e9cc3SRichard Henderson code within the TB. Therefore we do not update psw_n_nonzero. */ 691129e9cc3SRichard Henderson static void nullify_set(DisasContext *ctx, bool x) 692129e9cc3SRichard Henderson { 693129e9cc3SRichard Henderson if (ctx->psw_n_nonzero || x) { 694eaa3783bSRichard Henderson tcg_gen_movi_reg(cpu_psw_n, x); 695129e9cc3SRichard Henderson } 696129e9cc3SRichard Henderson } 697129e9cc3SRichard Henderson 698129e9cc3SRichard Henderson /* Mark the end of an instruction that may have been nullified. 69940f9f908SRichard Henderson This is the pair to nullify_over. Always returns true so that 70040f9f908SRichard Henderson it may be tail-called from a translate function. */ 70131234768SRichard Henderson static bool nullify_end(DisasContext *ctx) 702129e9cc3SRichard Henderson { 703129e9cc3SRichard Henderson TCGLabel *null_lab = ctx->null_lab; 70431234768SRichard Henderson DisasJumpType status = ctx->base.is_jmp; 705129e9cc3SRichard Henderson 706f49b3537SRichard Henderson /* For NEXT, NORETURN, STALE, we can easily continue (or exit). 707f49b3537SRichard Henderson For UPDATED, we cannot update on the nullified path. */ 708f49b3537SRichard Henderson assert(status != DISAS_IAQ_N_UPDATED); 709f49b3537SRichard Henderson 710129e9cc3SRichard Henderson if (likely(null_lab == NULL)) { 711129e9cc3SRichard Henderson /* The current insn wasn't conditional or handled the condition 712129e9cc3SRichard Henderson applied to it without a branch, so the (new) setting of 713129e9cc3SRichard Henderson NULL_COND can be applied directly to the next insn. */ 71431234768SRichard Henderson return true; 715129e9cc3SRichard Henderson } 716129e9cc3SRichard Henderson ctx->null_lab = NULL; 717129e9cc3SRichard Henderson 718129e9cc3SRichard Henderson if (likely(ctx->null_cond.c == TCG_COND_NEVER)) { 719129e9cc3SRichard Henderson /* The next instruction will be unconditional, 720129e9cc3SRichard Henderson and NULL_COND already reflects that. */ 721129e9cc3SRichard Henderson gen_set_label(null_lab); 722129e9cc3SRichard Henderson } else { 723129e9cc3SRichard Henderson /* The insn that we just executed is itself nullifying the next 724129e9cc3SRichard Henderson instruction. Store the condition in the PSW[N] global. 725129e9cc3SRichard Henderson We asserted PSW[N] = 0 in nullify_over, so that after the 726129e9cc3SRichard Henderson label we have the proper value in place. */ 727129e9cc3SRichard Henderson nullify_save(ctx); 728129e9cc3SRichard Henderson gen_set_label(null_lab); 729129e9cc3SRichard Henderson ctx->null_cond = cond_make_n(); 730129e9cc3SRichard Henderson } 731869051eaSRichard Henderson if (status == DISAS_NORETURN) { 73231234768SRichard Henderson ctx->base.is_jmp = DISAS_NEXT; 733129e9cc3SRichard Henderson } 73431234768SRichard Henderson return true; 735129e9cc3SRichard Henderson } 736129e9cc3SRichard Henderson 737eaa3783bSRichard Henderson static void copy_iaoq_entry(TCGv_reg dest, target_ureg ival, TCGv_reg vval) 73861766fe9SRichard Henderson { 73961766fe9SRichard Henderson if (unlikely(ival == -1)) { 740eaa3783bSRichard Henderson tcg_gen_mov_reg(dest, vval); 74161766fe9SRichard Henderson } else { 742eaa3783bSRichard Henderson tcg_gen_movi_reg(dest, ival); 74361766fe9SRichard Henderson } 74461766fe9SRichard Henderson } 74561766fe9SRichard Henderson 746eaa3783bSRichard Henderson static inline target_ureg iaoq_dest(DisasContext *ctx, target_sreg disp) 74761766fe9SRichard Henderson { 74861766fe9SRichard Henderson return ctx->iaoq_f + disp + 8; 74961766fe9SRichard Henderson } 75061766fe9SRichard Henderson 75161766fe9SRichard Henderson static void gen_excp_1(int exception) 75261766fe9SRichard Henderson { 75361766fe9SRichard Henderson TCGv_i32 t = tcg_const_i32(exception); 75461766fe9SRichard Henderson gen_helper_excp(cpu_env, t); 75561766fe9SRichard Henderson tcg_temp_free_i32(t); 75661766fe9SRichard Henderson } 75761766fe9SRichard Henderson 75831234768SRichard Henderson static void gen_excp(DisasContext *ctx, int exception) 75961766fe9SRichard Henderson { 76061766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 76161766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 762129e9cc3SRichard Henderson nullify_save(ctx); 76361766fe9SRichard Henderson gen_excp_1(exception); 76431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 76561766fe9SRichard Henderson } 76661766fe9SRichard Henderson 76731234768SRichard Henderson static bool gen_excp_iir(DisasContext *ctx, int exc) 7681a19da0dSRichard Henderson { 76931234768SRichard Henderson TCGv_reg tmp; 77031234768SRichard Henderson 77131234768SRichard Henderson nullify_over(ctx); 77231234768SRichard Henderson tmp = tcg_const_reg(ctx->insn); 7731a19da0dSRichard Henderson tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[CR_IIR])); 7741a19da0dSRichard Henderson tcg_temp_free(tmp); 77531234768SRichard Henderson gen_excp(ctx, exc); 77631234768SRichard Henderson return nullify_end(ctx); 7771a19da0dSRichard Henderson } 7781a19da0dSRichard Henderson 77931234768SRichard Henderson static bool gen_illegal(DisasContext *ctx) 78061766fe9SRichard Henderson { 78131234768SRichard Henderson return gen_excp_iir(ctx, EXCP_ILL); 78261766fe9SRichard Henderson } 78361766fe9SRichard Henderson 78440f9f908SRichard Henderson #ifdef CONFIG_USER_ONLY 78540f9f908SRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 78640f9f908SRichard Henderson return gen_excp_iir(ctx, EXCP) 78740f9f908SRichard Henderson #else 788e1b5a5edSRichard Henderson #define CHECK_MOST_PRIVILEGED(EXCP) \ 789e1b5a5edSRichard Henderson do { \ 790e1b5a5edSRichard Henderson if (ctx->privilege != 0) { \ 79131234768SRichard Henderson return gen_excp_iir(ctx, EXCP); \ 792e1b5a5edSRichard Henderson } \ 793e1b5a5edSRichard Henderson } while (0) 79440f9f908SRichard Henderson #endif 795e1b5a5edSRichard Henderson 796eaa3783bSRichard Henderson static bool use_goto_tb(DisasContext *ctx, target_ureg dest) 79761766fe9SRichard Henderson { 79861766fe9SRichard Henderson /* Suppress goto_tb in the case of single-steping and IO. */ 79931234768SRichard Henderson if ((tb_cflags(ctx->base.tb) & CF_LAST_IO) 80031234768SRichard Henderson || ctx->base.singlestep_enabled) { 80161766fe9SRichard Henderson return false; 80261766fe9SRichard Henderson } 80361766fe9SRichard Henderson return true; 80461766fe9SRichard Henderson } 80561766fe9SRichard Henderson 806129e9cc3SRichard Henderson /* If the next insn is to be nullified, and it's on the same page, 807129e9cc3SRichard Henderson and we're not attempting to set a breakpoint on it, then we can 808129e9cc3SRichard Henderson totally skip the nullified insn. This avoids creating and 809129e9cc3SRichard Henderson executing a TB that merely branches to the next TB. */ 810129e9cc3SRichard Henderson static bool use_nullify_skip(DisasContext *ctx) 811129e9cc3SRichard Henderson { 812129e9cc3SRichard Henderson return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0 813129e9cc3SRichard Henderson && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY)); 814129e9cc3SRichard Henderson } 815129e9cc3SRichard Henderson 81661766fe9SRichard Henderson static void gen_goto_tb(DisasContext *ctx, int which, 817eaa3783bSRichard Henderson target_ureg f, target_ureg b) 81861766fe9SRichard Henderson { 81961766fe9SRichard Henderson if (f != -1 && b != -1 && use_goto_tb(ctx, f)) { 82061766fe9SRichard Henderson tcg_gen_goto_tb(which); 821eaa3783bSRichard Henderson tcg_gen_movi_reg(cpu_iaoq_f, f); 822eaa3783bSRichard Henderson tcg_gen_movi_reg(cpu_iaoq_b, b); 82307ea28b4SRichard Henderson tcg_gen_exit_tb(ctx->base.tb, which); 82461766fe9SRichard Henderson } else { 82561766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b); 82661766fe9SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var); 827d01a3625SRichard Henderson if (ctx->base.singlestep_enabled) { 82861766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 82961766fe9SRichard Henderson } else { 8307f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 83161766fe9SRichard Henderson } 83261766fe9SRichard Henderson } 83361766fe9SRichard Henderson } 83461766fe9SRichard Henderson 835b2167459SRichard Henderson /* PA has a habit of taking the LSB of a field and using that as the sign, 836b2167459SRichard Henderson with the rest of the field becoming the least significant bits. */ 837eaa3783bSRichard Henderson static target_sreg low_sextract(uint32_t val, int pos, int len) 838b2167459SRichard Henderson { 839eaa3783bSRichard Henderson target_ureg x = -(target_ureg)extract32(val, pos, 1); 840b2167459SRichard Henderson x = (x << (len - 1)) | extract32(val, pos + 1, len - 1); 841b2167459SRichard Henderson return x; 842b2167459SRichard Henderson } 843b2167459SRichard Henderson 844ebe9383cSRichard Henderson static unsigned assemble_rt64(uint32_t insn) 845ebe9383cSRichard Henderson { 846ebe9383cSRichard Henderson unsigned r1 = extract32(insn, 6, 1); 847ebe9383cSRichard Henderson unsigned r0 = extract32(insn, 0, 5); 848ebe9383cSRichard Henderson return r1 * 32 + r0; 849ebe9383cSRichard Henderson } 850ebe9383cSRichard Henderson 851ebe9383cSRichard Henderson static unsigned assemble_ra64(uint32_t insn) 852ebe9383cSRichard Henderson { 853ebe9383cSRichard Henderson unsigned r1 = extract32(insn, 7, 1); 854ebe9383cSRichard Henderson unsigned r0 = extract32(insn, 21, 5); 855ebe9383cSRichard Henderson return r1 * 32 + r0; 856ebe9383cSRichard Henderson } 857ebe9383cSRichard Henderson 858ebe9383cSRichard Henderson static unsigned assemble_rb64(uint32_t insn) 859ebe9383cSRichard Henderson { 860ebe9383cSRichard Henderson unsigned r1 = extract32(insn, 12, 1); 861ebe9383cSRichard Henderson unsigned r0 = extract32(insn, 16, 5); 862ebe9383cSRichard Henderson return r1 * 32 + r0; 863ebe9383cSRichard Henderson } 864ebe9383cSRichard Henderson 865ebe9383cSRichard Henderson static unsigned assemble_rc64(uint32_t insn) 866ebe9383cSRichard Henderson { 867ebe9383cSRichard Henderson unsigned r2 = extract32(insn, 8, 1); 868ebe9383cSRichard Henderson unsigned r1 = extract32(insn, 13, 3); 869ebe9383cSRichard Henderson unsigned r0 = extract32(insn, 9, 2); 870ebe9383cSRichard Henderson return r2 * 32 + r1 * 4 + r0; 871ebe9383cSRichard Henderson } 872ebe9383cSRichard Henderson 873c603e14aSRichard Henderson static inline unsigned assemble_sr3(uint32_t insn) 87433423472SRichard Henderson { 87533423472SRichard Henderson unsigned s2 = extract32(insn, 13, 1); 87633423472SRichard Henderson unsigned s0 = extract32(insn, 14, 2); 87733423472SRichard Henderson return s2 * 4 + s0; 87833423472SRichard Henderson } 87933423472SRichard Henderson 880eaa3783bSRichard Henderson static target_sreg assemble_16(uint32_t insn) 881b2167459SRichard Henderson { 882b2167459SRichard Henderson /* Take the name from PA2.0, which produces a 16-bit number 883b2167459SRichard Henderson only with wide mode; otherwise a 14-bit number. Since we don't 884b2167459SRichard Henderson implement wide mode, this is always the 14-bit number. */ 885b2167459SRichard Henderson return low_sextract(insn, 0, 14); 886b2167459SRichard Henderson } 887b2167459SRichard Henderson 888eaa3783bSRichard Henderson static target_sreg assemble_16a(uint32_t insn) 88996d6407fSRichard Henderson { 89096d6407fSRichard Henderson /* Take the name from PA2.0, which produces a 14-bit shifted number 89196d6407fSRichard Henderson only with wide mode; otherwise a 12-bit shifted number. Since we 89296d6407fSRichard Henderson don't implement wide mode, this is always the 12-bit number. */ 893eaa3783bSRichard Henderson target_ureg x = -(target_ureg)(insn & 1); 89496d6407fSRichard Henderson x = (x << 11) | extract32(insn, 2, 11); 89596d6407fSRichard Henderson return x << 2; 89696d6407fSRichard Henderson } 89796d6407fSRichard Henderson 898eaa3783bSRichard Henderson static target_sreg assemble_21(uint32_t insn) 899b2167459SRichard Henderson { 900eaa3783bSRichard Henderson target_ureg x = -(target_ureg)(insn & 1); 901b2167459SRichard Henderson x = (x << 11) | extract32(insn, 1, 11); 902b2167459SRichard Henderson x = (x << 2) | extract32(insn, 14, 2); 903b2167459SRichard Henderson x = (x << 5) | extract32(insn, 16, 5); 904b2167459SRichard Henderson x = (x << 2) | extract32(insn, 12, 2); 905b2167459SRichard Henderson return x << 11; 906b2167459SRichard Henderson } 907b2167459SRichard Henderson 908b2167459SRichard Henderson /* The parisc documentation describes only the general interpretation of 909b2167459SRichard Henderson the conditions, without describing their exact implementation. The 910b2167459SRichard Henderson interpretations do not stand up well when considering ADD,C and SUB,B. 911b2167459SRichard Henderson However, considering the Addition, Subtraction and Logical conditions 912b2167459SRichard Henderson as a whole it would appear that these relations are similar to what 913b2167459SRichard Henderson a traditional NZCV set of flags would produce. */ 914b2167459SRichard Henderson 915eaa3783bSRichard Henderson static DisasCond do_cond(unsigned cf, TCGv_reg res, 916eaa3783bSRichard Henderson TCGv_reg cb_msb, TCGv_reg sv) 917b2167459SRichard Henderson { 918b2167459SRichard Henderson DisasCond cond; 919eaa3783bSRichard Henderson TCGv_reg tmp; 920b2167459SRichard Henderson 921b2167459SRichard Henderson switch (cf >> 1) { 922b2167459SRichard Henderson case 0: /* Never / TR */ 923b2167459SRichard Henderson cond = cond_make_f(); 924b2167459SRichard Henderson break; 925b2167459SRichard Henderson case 1: /* = / <> (Z / !Z) */ 926b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, res); 927b2167459SRichard Henderson break; 928b2167459SRichard Henderson case 2: /* < / >= (N / !N) */ 929b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, res); 930b2167459SRichard Henderson break; 931b2167459SRichard Henderson case 3: /* <= / > (N | Z / !N & !Z) */ 932b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LE, res); 933b2167459SRichard Henderson break; 934b2167459SRichard Henderson case 4: /* NUV / UV (!C / C) */ 935b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, cb_msb); 936b2167459SRichard Henderson break; 937b2167459SRichard Henderson case 5: /* ZNV / VNZ (!C | Z / C & !Z) */ 938b2167459SRichard Henderson tmp = tcg_temp_new(); 939eaa3783bSRichard Henderson tcg_gen_neg_reg(tmp, cb_msb); 940eaa3783bSRichard Henderson tcg_gen_and_reg(tmp, tmp, res); 941b2167459SRichard Henderson cond = cond_make_0(TCG_COND_EQ, tmp); 942b2167459SRichard Henderson tcg_temp_free(tmp); 943b2167459SRichard Henderson break; 944b2167459SRichard Henderson case 6: /* SV / NSV (V / !V) */ 945b2167459SRichard Henderson cond = cond_make_0(TCG_COND_LT, sv); 946b2167459SRichard Henderson break; 947b2167459SRichard Henderson case 7: /* OD / EV */ 948b2167459SRichard Henderson tmp = tcg_temp_new(); 949eaa3783bSRichard Henderson tcg_gen_andi_reg(tmp, res, 1); 950b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 951b2167459SRichard Henderson tcg_temp_free(tmp); 952b2167459SRichard Henderson break; 953b2167459SRichard Henderson default: 954b2167459SRichard Henderson g_assert_not_reached(); 955b2167459SRichard Henderson } 956b2167459SRichard Henderson if (cf & 1) { 957b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 958b2167459SRichard Henderson } 959b2167459SRichard Henderson 960b2167459SRichard Henderson return cond; 961b2167459SRichard Henderson } 962b2167459SRichard Henderson 963b2167459SRichard Henderson /* Similar, but for the special case of subtraction without borrow, we 964b2167459SRichard Henderson can use the inputs directly. This can allow other computation to be 965b2167459SRichard Henderson deleted as unused. */ 966b2167459SRichard Henderson 967eaa3783bSRichard Henderson static DisasCond do_sub_cond(unsigned cf, TCGv_reg res, 968eaa3783bSRichard Henderson TCGv_reg in1, TCGv_reg in2, TCGv_reg sv) 969b2167459SRichard Henderson { 970b2167459SRichard Henderson DisasCond cond; 971b2167459SRichard Henderson 972b2167459SRichard Henderson switch (cf >> 1) { 973b2167459SRichard Henderson case 1: /* = / <> */ 974b2167459SRichard Henderson cond = cond_make(TCG_COND_EQ, in1, in2); 975b2167459SRichard Henderson break; 976b2167459SRichard Henderson case 2: /* < / >= */ 977b2167459SRichard Henderson cond = cond_make(TCG_COND_LT, in1, in2); 978b2167459SRichard Henderson break; 979b2167459SRichard Henderson case 3: /* <= / > */ 980b2167459SRichard Henderson cond = cond_make(TCG_COND_LE, in1, in2); 981b2167459SRichard Henderson break; 982b2167459SRichard Henderson case 4: /* << / >>= */ 983b2167459SRichard Henderson cond = cond_make(TCG_COND_LTU, in1, in2); 984b2167459SRichard Henderson break; 985b2167459SRichard Henderson case 5: /* <<= / >> */ 986b2167459SRichard Henderson cond = cond_make(TCG_COND_LEU, in1, in2); 987b2167459SRichard Henderson break; 988b2167459SRichard Henderson default: 989b2167459SRichard Henderson return do_cond(cf, res, sv, sv); 990b2167459SRichard Henderson } 991b2167459SRichard Henderson if (cf & 1) { 992b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 993b2167459SRichard Henderson } 994b2167459SRichard Henderson 995b2167459SRichard Henderson return cond; 996b2167459SRichard Henderson } 997b2167459SRichard Henderson 998b2167459SRichard Henderson /* Similar, but for logicals, where the carry and overflow bits are not 999b2167459SRichard Henderson computed, and use of them is undefined. */ 1000b2167459SRichard Henderson 1001eaa3783bSRichard Henderson static DisasCond do_log_cond(unsigned cf, TCGv_reg res) 1002b2167459SRichard Henderson { 1003b2167459SRichard Henderson switch (cf >> 1) { 1004b2167459SRichard Henderson case 4: case 5: case 6: 1005b2167459SRichard Henderson cf &= 1; 1006b2167459SRichard Henderson break; 1007b2167459SRichard Henderson } 1008b2167459SRichard Henderson return do_cond(cf, res, res, res); 1009b2167459SRichard Henderson } 1010b2167459SRichard Henderson 101198cd9ca7SRichard Henderson /* Similar, but for shift/extract/deposit conditions. */ 101298cd9ca7SRichard Henderson 1013eaa3783bSRichard Henderson static DisasCond do_sed_cond(unsigned orig, TCGv_reg res) 101498cd9ca7SRichard Henderson { 101598cd9ca7SRichard Henderson unsigned c, f; 101698cd9ca7SRichard Henderson 101798cd9ca7SRichard Henderson /* Convert the compressed condition codes to standard. 101898cd9ca7SRichard Henderson 0-2 are the same as logicals (nv,<,<=), while 3 is OD. 101998cd9ca7SRichard Henderson 4-7 are the reverse of 0-3. */ 102098cd9ca7SRichard Henderson c = orig & 3; 102198cd9ca7SRichard Henderson if (c == 3) { 102298cd9ca7SRichard Henderson c = 7; 102398cd9ca7SRichard Henderson } 102498cd9ca7SRichard Henderson f = (orig & 4) / 4; 102598cd9ca7SRichard Henderson 102698cd9ca7SRichard Henderson return do_log_cond(c * 2 + f, res); 102798cd9ca7SRichard Henderson } 102898cd9ca7SRichard Henderson 1029b2167459SRichard Henderson /* Similar, but for unit conditions. */ 1030b2167459SRichard Henderson 1031eaa3783bSRichard Henderson static DisasCond do_unit_cond(unsigned cf, TCGv_reg res, 1032eaa3783bSRichard Henderson TCGv_reg in1, TCGv_reg in2) 1033b2167459SRichard Henderson { 1034b2167459SRichard Henderson DisasCond cond; 1035eaa3783bSRichard Henderson TCGv_reg tmp, cb = NULL; 1036b2167459SRichard Henderson 1037b2167459SRichard Henderson if (cf & 8) { 1038b2167459SRichard Henderson /* Since we want to test lots of carry-out bits all at once, do not 1039b2167459SRichard Henderson * do our normal thing and compute carry-in of bit B+1 since that 1040b2167459SRichard Henderson * leaves us with carry bits spread across two words. 1041b2167459SRichard Henderson */ 1042b2167459SRichard Henderson cb = tcg_temp_new(); 1043b2167459SRichard Henderson tmp = tcg_temp_new(); 1044eaa3783bSRichard Henderson tcg_gen_or_reg(cb, in1, in2); 1045eaa3783bSRichard Henderson tcg_gen_and_reg(tmp, in1, in2); 1046eaa3783bSRichard Henderson tcg_gen_andc_reg(cb, cb, res); 1047eaa3783bSRichard Henderson tcg_gen_or_reg(cb, cb, tmp); 1048b2167459SRichard Henderson tcg_temp_free(tmp); 1049b2167459SRichard Henderson } 1050b2167459SRichard Henderson 1051b2167459SRichard Henderson switch (cf >> 1) { 1052b2167459SRichard Henderson case 0: /* never / TR */ 1053b2167459SRichard Henderson case 1: /* undefined */ 1054b2167459SRichard Henderson case 5: /* undefined */ 1055b2167459SRichard Henderson cond = cond_make_f(); 1056b2167459SRichard Henderson break; 1057b2167459SRichard Henderson 1058b2167459SRichard Henderson case 2: /* SBZ / NBZ */ 1059b2167459SRichard Henderson /* See hasless(v,1) from 1060b2167459SRichard Henderson * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord 1061b2167459SRichard Henderson */ 1062b2167459SRichard Henderson tmp = tcg_temp_new(); 1063eaa3783bSRichard Henderson tcg_gen_subi_reg(tmp, res, 0x01010101u); 1064eaa3783bSRichard Henderson tcg_gen_andc_reg(tmp, tmp, res); 1065eaa3783bSRichard Henderson tcg_gen_andi_reg(tmp, tmp, 0x80808080u); 1066b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 1067b2167459SRichard Henderson tcg_temp_free(tmp); 1068b2167459SRichard Henderson break; 1069b2167459SRichard Henderson 1070b2167459SRichard Henderson case 3: /* SHZ / NHZ */ 1071b2167459SRichard Henderson tmp = tcg_temp_new(); 1072eaa3783bSRichard Henderson tcg_gen_subi_reg(tmp, res, 0x00010001u); 1073eaa3783bSRichard Henderson tcg_gen_andc_reg(tmp, tmp, res); 1074eaa3783bSRichard Henderson tcg_gen_andi_reg(tmp, tmp, 0x80008000u); 1075b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, tmp); 1076b2167459SRichard Henderson tcg_temp_free(tmp); 1077b2167459SRichard Henderson break; 1078b2167459SRichard Henderson 1079b2167459SRichard Henderson case 4: /* SDC / NDC */ 1080eaa3783bSRichard Henderson tcg_gen_andi_reg(cb, cb, 0x88888888u); 1081b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 1082b2167459SRichard Henderson break; 1083b2167459SRichard Henderson 1084b2167459SRichard Henderson case 6: /* SBC / NBC */ 1085eaa3783bSRichard Henderson tcg_gen_andi_reg(cb, cb, 0x80808080u); 1086b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 1087b2167459SRichard Henderson break; 1088b2167459SRichard Henderson 1089b2167459SRichard Henderson case 7: /* SHC / NHC */ 1090eaa3783bSRichard Henderson tcg_gen_andi_reg(cb, cb, 0x80008000u); 1091b2167459SRichard Henderson cond = cond_make_0(TCG_COND_NE, cb); 1092b2167459SRichard Henderson break; 1093b2167459SRichard Henderson 1094b2167459SRichard Henderson default: 1095b2167459SRichard Henderson g_assert_not_reached(); 1096b2167459SRichard Henderson } 1097b2167459SRichard Henderson if (cf & 8) { 1098b2167459SRichard Henderson tcg_temp_free(cb); 1099b2167459SRichard Henderson } 1100b2167459SRichard Henderson if (cf & 1) { 1101b2167459SRichard Henderson cond.c = tcg_invert_cond(cond.c); 1102b2167459SRichard Henderson } 1103b2167459SRichard Henderson 1104b2167459SRichard Henderson return cond; 1105b2167459SRichard Henderson } 1106b2167459SRichard Henderson 1107b2167459SRichard Henderson /* Compute signed overflow for addition. */ 1108eaa3783bSRichard Henderson static TCGv_reg do_add_sv(DisasContext *ctx, TCGv_reg res, 1109eaa3783bSRichard Henderson TCGv_reg in1, TCGv_reg in2) 1110b2167459SRichard Henderson { 1111eaa3783bSRichard Henderson TCGv_reg sv = get_temp(ctx); 1112eaa3783bSRichard Henderson TCGv_reg tmp = tcg_temp_new(); 1113b2167459SRichard Henderson 1114eaa3783bSRichard Henderson tcg_gen_xor_reg(sv, res, in1); 1115eaa3783bSRichard Henderson tcg_gen_xor_reg(tmp, in1, in2); 1116eaa3783bSRichard Henderson tcg_gen_andc_reg(sv, sv, tmp); 1117b2167459SRichard Henderson tcg_temp_free(tmp); 1118b2167459SRichard Henderson 1119b2167459SRichard Henderson return sv; 1120b2167459SRichard Henderson } 1121b2167459SRichard Henderson 1122b2167459SRichard Henderson /* Compute signed overflow for subtraction. */ 1123eaa3783bSRichard Henderson static TCGv_reg do_sub_sv(DisasContext *ctx, TCGv_reg res, 1124eaa3783bSRichard Henderson TCGv_reg in1, TCGv_reg in2) 1125b2167459SRichard Henderson { 1126eaa3783bSRichard Henderson TCGv_reg sv = get_temp(ctx); 1127eaa3783bSRichard Henderson TCGv_reg tmp = tcg_temp_new(); 1128b2167459SRichard Henderson 1129eaa3783bSRichard Henderson tcg_gen_xor_reg(sv, res, in1); 1130eaa3783bSRichard Henderson tcg_gen_xor_reg(tmp, in1, in2); 1131eaa3783bSRichard Henderson tcg_gen_and_reg(sv, sv, tmp); 1132b2167459SRichard Henderson tcg_temp_free(tmp); 1133b2167459SRichard Henderson 1134b2167459SRichard Henderson return sv; 1135b2167459SRichard Henderson } 1136b2167459SRichard Henderson 113731234768SRichard Henderson static void do_add(DisasContext *ctx, unsigned rt, TCGv_reg in1, 1138eaa3783bSRichard Henderson TCGv_reg in2, unsigned shift, bool is_l, 1139eaa3783bSRichard Henderson bool is_tsv, bool is_tc, bool is_c, unsigned cf) 1140b2167459SRichard Henderson { 1141eaa3783bSRichard Henderson TCGv_reg dest, cb, cb_msb, sv, tmp; 1142b2167459SRichard Henderson unsigned c = cf >> 1; 1143b2167459SRichard Henderson DisasCond cond; 1144b2167459SRichard Henderson 1145b2167459SRichard Henderson dest = tcg_temp_new(); 1146f764718dSRichard Henderson cb = NULL; 1147f764718dSRichard Henderson cb_msb = NULL; 1148b2167459SRichard Henderson 1149b2167459SRichard Henderson if (shift) { 1150b2167459SRichard Henderson tmp = get_temp(ctx); 1151eaa3783bSRichard Henderson tcg_gen_shli_reg(tmp, in1, shift); 1152b2167459SRichard Henderson in1 = tmp; 1153b2167459SRichard Henderson } 1154b2167459SRichard Henderson 1155b2167459SRichard Henderson if (!is_l || c == 4 || c == 5) { 1156eaa3783bSRichard Henderson TCGv_reg zero = tcg_const_reg(0); 1157b2167459SRichard Henderson cb_msb = get_temp(ctx); 1158eaa3783bSRichard Henderson tcg_gen_add2_reg(dest, cb_msb, in1, zero, in2, zero); 1159b2167459SRichard Henderson if (is_c) { 1160eaa3783bSRichard Henderson tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero); 1161b2167459SRichard Henderson } 1162b2167459SRichard Henderson tcg_temp_free(zero); 1163b2167459SRichard Henderson if (!is_l) { 1164b2167459SRichard Henderson cb = get_temp(ctx); 1165eaa3783bSRichard Henderson tcg_gen_xor_reg(cb, in1, in2); 1166eaa3783bSRichard Henderson tcg_gen_xor_reg(cb, cb, dest); 1167b2167459SRichard Henderson } 1168b2167459SRichard Henderson } else { 1169eaa3783bSRichard Henderson tcg_gen_add_reg(dest, in1, in2); 1170b2167459SRichard Henderson if (is_c) { 1171eaa3783bSRichard Henderson tcg_gen_add_reg(dest, dest, cpu_psw_cb_msb); 1172b2167459SRichard Henderson } 1173b2167459SRichard Henderson } 1174b2167459SRichard Henderson 1175b2167459SRichard Henderson /* Compute signed overflow if required. */ 1176f764718dSRichard Henderson sv = NULL; 1177b2167459SRichard Henderson if (is_tsv || c == 6) { 1178b2167459SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 1179b2167459SRichard Henderson if (is_tsv) { 1180b2167459SRichard Henderson /* ??? Need to include overflow from shift. */ 1181b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 1182b2167459SRichard Henderson } 1183b2167459SRichard Henderson } 1184b2167459SRichard Henderson 1185b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1186b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 1187b2167459SRichard Henderson if (is_tc) { 1188b2167459SRichard Henderson cond_prep(&cond); 1189b2167459SRichard Henderson tmp = tcg_temp_new(); 1190eaa3783bSRichard Henderson tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); 1191b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 1192b2167459SRichard Henderson tcg_temp_free(tmp); 1193b2167459SRichard Henderson } 1194b2167459SRichard Henderson 1195b2167459SRichard Henderson /* Write back the result. */ 1196b2167459SRichard Henderson if (!is_l) { 1197b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1198b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1199b2167459SRichard Henderson } 1200b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1201b2167459SRichard Henderson tcg_temp_free(dest); 1202b2167459SRichard Henderson 1203b2167459SRichard Henderson /* Install the new nullification. */ 1204b2167459SRichard Henderson cond_free(&ctx->null_cond); 1205b2167459SRichard Henderson ctx->null_cond = cond; 1206b2167459SRichard Henderson } 1207b2167459SRichard Henderson 12080c982a28SRichard Henderson static bool do_add_reg(DisasContext *ctx, arg_rrr_cf_sh *a, 12090c982a28SRichard Henderson bool is_l, bool is_tsv, bool is_tc, bool is_c) 12100c982a28SRichard Henderson { 12110c982a28SRichard Henderson TCGv_reg tcg_r1, tcg_r2; 12120c982a28SRichard Henderson 12130c982a28SRichard Henderson if (a->cf) { 12140c982a28SRichard Henderson nullify_over(ctx); 12150c982a28SRichard Henderson } 12160c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12170c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 12180c982a28SRichard Henderson do_add(ctx, a->t, tcg_r1, tcg_r2, a->sh, is_l, is_tsv, is_tc, is_c, a->cf); 12190c982a28SRichard Henderson return nullify_end(ctx); 12200c982a28SRichard Henderson } 12210c982a28SRichard Henderson 122231234768SRichard Henderson static void do_sub(DisasContext *ctx, unsigned rt, TCGv_reg in1, 1223eaa3783bSRichard Henderson TCGv_reg in2, bool is_tsv, bool is_b, 1224eaa3783bSRichard Henderson bool is_tc, unsigned cf) 1225b2167459SRichard Henderson { 1226eaa3783bSRichard Henderson TCGv_reg dest, sv, cb, cb_msb, zero, tmp; 1227b2167459SRichard Henderson unsigned c = cf >> 1; 1228b2167459SRichard Henderson DisasCond cond; 1229b2167459SRichard Henderson 1230b2167459SRichard Henderson dest = tcg_temp_new(); 1231b2167459SRichard Henderson cb = tcg_temp_new(); 1232b2167459SRichard Henderson cb_msb = tcg_temp_new(); 1233b2167459SRichard Henderson 1234eaa3783bSRichard Henderson zero = tcg_const_reg(0); 1235b2167459SRichard Henderson if (is_b) { 1236b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + C. */ 1237eaa3783bSRichard Henderson tcg_gen_not_reg(cb, in2); 1238eaa3783bSRichard Henderson tcg_gen_add2_reg(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero); 1239eaa3783bSRichard Henderson tcg_gen_add2_reg(dest, cb_msb, dest, cb_msb, cb, zero); 1240eaa3783bSRichard Henderson tcg_gen_xor_reg(cb, cb, in1); 1241eaa3783bSRichard Henderson tcg_gen_xor_reg(cb, cb, dest); 1242b2167459SRichard Henderson } else { 1243b2167459SRichard Henderson /* DEST,C = IN1 + ~IN2 + 1. We can produce the same result in fewer 1244b2167459SRichard Henderson operations by seeding the high word with 1 and subtracting. */ 1245eaa3783bSRichard Henderson tcg_gen_movi_reg(cb_msb, 1); 1246eaa3783bSRichard Henderson tcg_gen_sub2_reg(dest, cb_msb, in1, cb_msb, in2, zero); 1247eaa3783bSRichard Henderson tcg_gen_eqv_reg(cb, in1, in2); 1248eaa3783bSRichard Henderson tcg_gen_xor_reg(cb, cb, dest); 1249b2167459SRichard Henderson } 1250b2167459SRichard Henderson tcg_temp_free(zero); 1251b2167459SRichard Henderson 1252b2167459SRichard Henderson /* Compute signed overflow if required. */ 1253f764718dSRichard Henderson sv = NULL; 1254b2167459SRichard Henderson if (is_tsv || c == 6) { 1255b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1256b2167459SRichard Henderson if (is_tsv) { 1257b2167459SRichard Henderson gen_helper_tsv(cpu_env, sv); 1258b2167459SRichard Henderson } 1259b2167459SRichard Henderson } 1260b2167459SRichard Henderson 1261b2167459SRichard Henderson /* Compute the condition. We cannot use the special case for borrow. */ 1262b2167459SRichard Henderson if (!is_b) { 1263b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 1264b2167459SRichard Henderson } else { 1265b2167459SRichard Henderson cond = do_cond(cf, dest, cb_msb, sv); 1266b2167459SRichard Henderson } 1267b2167459SRichard Henderson 1268b2167459SRichard Henderson /* Emit any conditional trap before any writeback. */ 1269b2167459SRichard Henderson if (is_tc) { 1270b2167459SRichard Henderson cond_prep(&cond); 1271b2167459SRichard Henderson tmp = tcg_temp_new(); 1272eaa3783bSRichard Henderson tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); 1273b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 1274b2167459SRichard Henderson tcg_temp_free(tmp); 1275b2167459SRichard Henderson } 1276b2167459SRichard Henderson 1277b2167459SRichard Henderson /* Write back the result. */ 1278b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb, cb); 1279b2167459SRichard Henderson save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb); 1280b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1281b2167459SRichard Henderson tcg_temp_free(dest); 1282b2167459SRichard Henderson 1283b2167459SRichard Henderson /* Install the new nullification. */ 1284b2167459SRichard Henderson cond_free(&ctx->null_cond); 1285b2167459SRichard Henderson ctx->null_cond = cond; 1286b2167459SRichard Henderson } 1287b2167459SRichard Henderson 12880c982a28SRichard Henderson static bool do_sub_reg(DisasContext *ctx, arg_rrr_cf *a, 12890c982a28SRichard Henderson bool is_tsv, bool is_b, bool is_tc) 12900c982a28SRichard Henderson { 12910c982a28SRichard Henderson TCGv_reg tcg_r1, tcg_r2; 12920c982a28SRichard Henderson 12930c982a28SRichard Henderson if (a->cf) { 12940c982a28SRichard Henderson nullify_over(ctx); 12950c982a28SRichard Henderson } 12960c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 12970c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 12980c982a28SRichard Henderson do_sub(ctx, a->t, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, a->cf); 12990c982a28SRichard Henderson return nullify_end(ctx); 13000c982a28SRichard Henderson } 13010c982a28SRichard Henderson 130231234768SRichard Henderson static void do_cmpclr(DisasContext *ctx, unsigned rt, TCGv_reg in1, 1303eaa3783bSRichard Henderson TCGv_reg in2, unsigned cf) 1304b2167459SRichard Henderson { 1305eaa3783bSRichard Henderson TCGv_reg dest, sv; 1306b2167459SRichard Henderson DisasCond cond; 1307b2167459SRichard Henderson 1308b2167459SRichard Henderson dest = tcg_temp_new(); 1309eaa3783bSRichard Henderson tcg_gen_sub_reg(dest, in1, in2); 1310b2167459SRichard Henderson 1311b2167459SRichard Henderson /* Compute signed overflow if required. */ 1312f764718dSRichard Henderson sv = NULL; 1313b2167459SRichard Henderson if ((cf >> 1) == 6) { 1314b2167459SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 1315b2167459SRichard Henderson } 1316b2167459SRichard Henderson 1317b2167459SRichard Henderson /* Form the condition for the compare. */ 1318b2167459SRichard Henderson cond = do_sub_cond(cf, dest, in1, in2, sv); 1319b2167459SRichard Henderson 1320b2167459SRichard Henderson /* Clear. */ 1321eaa3783bSRichard Henderson tcg_gen_movi_reg(dest, 0); 1322b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1323b2167459SRichard Henderson tcg_temp_free(dest); 1324b2167459SRichard Henderson 1325b2167459SRichard Henderson /* Install the new nullification. */ 1326b2167459SRichard Henderson cond_free(&ctx->null_cond); 1327b2167459SRichard Henderson ctx->null_cond = cond; 1328b2167459SRichard Henderson } 1329b2167459SRichard Henderson 133031234768SRichard Henderson static void do_log(DisasContext *ctx, unsigned rt, TCGv_reg in1, 1331eaa3783bSRichard Henderson TCGv_reg in2, unsigned cf, 1332eaa3783bSRichard Henderson void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg)) 1333b2167459SRichard Henderson { 1334eaa3783bSRichard Henderson TCGv_reg dest = dest_gpr(ctx, rt); 1335b2167459SRichard Henderson 1336b2167459SRichard Henderson /* Perform the operation, and writeback. */ 1337b2167459SRichard Henderson fn(dest, in1, in2); 1338b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1339b2167459SRichard Henderson 1340b2167459SRichard Henderson /* Install the new nullification. */ 1341b2167459SRichard Henderson cond_free(&ctx->null_cond); 1342b2167459SRichard Henderson if (cf) { 1343b2167459SRichard Henderson ctx->null_cond = do_log_cond(cf, dest); 1344b2167459SRichard Henderson } 1345b2167459SRichard Henderson } 1346b2167459SRichard Henderson 13470c982a28SRichard Henderson static bool do_log_reg(DisasContext *ctx, arg_rrr_cf *a, 13480c982a28SRichard Henderson void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg)) 13490c982a28SRichard Henderson { 13500c982a28SRichard Henderson TCGv_reg tcg_r1, tcg_r2; 13510c982a28SRichard Henderson 13520c982a28SRichard Henderson if (a->cf) { 13530c982a28SRichard Henderson nullify_over(ctx); 13540c982a28SRichard Henderson } 13550c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 13560c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 13570c982a28SRichard Henderson do_log(ctx, a->t, tcg_r1, tcg_r2, a->cf, fn); 13580c982a28SRichard Henderson return nullify_end(ctx); 13590c982a28SRichard Henderson } 13600c982a28SRichard Henderson 136131234768SRichard Henderson static void do_unit(DisasContext *ctx, unsigned rt, TCGv_reg in1, 1362eaa3783bSRichard Henderson TCGv_reg in2, unsigned cf, bool is_tc, 1363eaa3783bSRichard Henderson void (*fn)(TCGv_reg, TCGv_reg, TCGv_reg)) 1364b2167459SRichard Henderson { 1365eaa3783bSRichard Henderson TCGv_reg dest; 1366b2167459SRichard Henderson DisasCond cond; 1367b2167459SRichard Henderson 1368b2167459SRichard Henderson if (cf == 0) { 1369b2167459SRichard Henderson dest = dest_gpr(ctx, rt); 1370b2167459SRichard Henderson fn(dest, in1, in2); 1371b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1372b2167459SRichard Henderson cond_free(&ctx->null_cond); 1373b2167459SRichard Henderson } else { 1374b2167459SRichard Henderson dest = tcg_temp_new(); 1375b2167459SRichard Henderson fn(dest, in1, in2); 1376b2167459SRichard Henderson 1377b2167459SRichard Henderson cond = do_unit_cond(cf, dest, in1, in2); 1378b2167459SRichard Henderson 1379b2167459SRichard Henderson if (is_tc) { 1380eaa3783bSRichard Henderson TCGv_reg tmp = tcg_temp_new(); 1381b2167459SRichard Henderson cond_prep(&cond); 1382eaa3783bSRichard Henderson tcg_gen_setcond_reg(cond.c, tmp, cond.a0, cond.a1); 1383b2167459SRichard Henderson gen_helper_tcond(cpu_env, tmp); 1384b2167459SRichard Henderson tcg_temp_free(tmp); 1385b2167459SRichard Henderson } 1386b2167459SRichard Henderson save_gpr(ctx, rt, dest); 1387b2167459SRichard Henderson 1388b2167459SRichard Henderson cond_free(&ctx->null_cond); 1389b2167459SRichard Henderson ctx->null_cond = cond; 1390b2167459SRichard Henderson } 1391b2167459SRichard Henderson } 1392b2167459SRichard Henderson 139386f8d05fSRichard Henderson #ifndef CONFIG_USER_ONLY 13948d6ae7fbSRichard Henderson /* The "normal" usage is SP >= 0, wherein SP == 0 selects the space 13958d6ae7fbSRichard Henderson from the top 2 bits of the base register. There are a few system 13968d6ae7fbSRichard Henderson instructions that have a 3-bit space specifier, for which SR0 is 13978d6ae7fbSRichard Henderson not special. To handle this, pass ~SP. */ 139886f8d05fSRichard Henderson static TCGv_i64 space_select(DisasContext *ctx, int sp, TCGv_reg base) 139986f8d05fSRichard Henderson { 140086f8d05fSRichard Henderson TCGv_ptr ptr; 140186f8d05fSRichard Henderson TCGv_reg tmp; 140286f8d05fSRichard Henderson TCGv_i64 spc; 140386f8d05fSRichard Henderson 140486f8d05fSRichard Henderson if (sp != 0) { 14058d6ae7fbSRichard Henderson if (sp < 0) { 14068d6ae7fbSRichard Henderson sp = ~sp; 14078d6ae7fbSRichard Henderson } 14088d6ae7fbSRichard Henderson spc = get_temp_tl(ctx); 14098d6ae7fbSRichard Henderson load_spr(ctx, spc, sp); 14108d6ae7fbSRichard Henderson return spc; 141186f8d05fSRichard Henderson } 1412494737b7SRichard Henderson if (ctx->tb_flags & TB_FLAG_SR_SAME) { 1413494737b7SRichard Henderson return cpu_srH; 1414494737b7SRichard Henderson } 141586f8d05fSRichard Henderson 141686f8d05fSRichard Henderson ptr = tcg_temp_new_ptr(); 141786f8d05fSRichard Henderson tmp = tcg_temp_new(); 141886f8d05fSRichard Henderson spc = get_temp_tl(ctx); 141986f8d05fSRichard Henderson 142086f8d05fSRichard Henderson tcg_gen_shri_reg(tmp, base, TARGET_REGISTER_BITS - 5); 142186f8d05fSRichard Henderson tcg_gen_andi_reg(tmp, tmp, 030); 142286f8d05fSRichard Henderson tcg_gen_trunc_reg_ptr(ptr, tmp); 142386f8d05fSRichard Henderson tcg_temp_free(tmp); 142486f8d05fSRichard Henderson 142586f8d05fSRichard Henderson tcg_gen_add_ptr(ptr, ptr, cpu_env); 142686f8d05fSRichard Henderson tcg_gen_ld_i64(spc, ptr, offsetof(CPUHPPAState, sr[4])); 142786f8d05fSRichard Henderson tcg_temp_free_ptr(ptr); 142886f8d05fSRichard Henderson 142986f8d05fSRichard Henderson return spc; 143086f8d05fSRichard Henderson } 143186f8d05fSRichard Henderson #endif 143286f8d05fSRichard Henderson 143386f8d05fSRichard Henderson static void form_gva(DisasContext *ctx, TCGv_tl *pgva, TCGv_reg *pofs, 143486f8d05fSRichard Henderson unsigned rb, unsigned rx, int scale, target_sreg disp, 143586f8d05fSRichard Henderson unsigned sp, int modify, bool is_phys) 143686f8d05fSRichard Henderson { 143786f8d05fSRichard Henderson TCGv_reg base = load_gpr(ctx, rb); 143886f8d05fSRichard Henderson TCGv_reg ofs; 143986f8d05fSRichard Henderson 144086f8d05fSRichard Henderson /* Note that RX is mutually exclusive with DISP. */ 144186f8d05fSRichard Henderson if (rx) { 144286f8d05fSRichard Henderson ofs = get_temp(ctx); 144386f8d05fSRichard Henderson tcg_gen_shli_reg(ofs, cpu_gr[rx], scale); 144486f8d05fSRichard Henderson tcg_gen_add_reg(ofs, ofs, base); 144586f8d05fSRichard Henderson } else if (disp || modify) { 144686f8d05fSRichard Henderson ofs = get_temp(ctx); 144786f8d05fSRichard Henderson tcg_gen_addi_reg(ofs, base, disp); 144886f8d05fSRichard Henderson } else { 144986f8d05fSRichard Henderson ofs = base; 145086f8d05fSRichard Henderson } 145186f8d05fSRichard Henderson 145286f8d05fSRichard Henderson *pofs = ofs; 145386f8d05fSRichard Henderson #ifdef CONFIG_USER_ONLY 145486f8d05fSRichard Henderson *pgva = (modify <= 0 ? ofs : base); 145586f8d05fSRichard Henderson #else 145686f8d05fSRichard Henderson TCGv_tl addr = get_temp_tl(ctx); 145786f8d05fSRichard Henderson tcg_gen_extu_reg_tl(addr, modify <= 0 ? ofs : base); 1458494737b7SRichard Henderson if (ctx->tb_flags & PSW_W) { 145986f8d05fSRichard Henderson tcg_gen_andi_tl(addr, addr, 0x3fffffffffffffffull); 146086f8d05fSRichard Henderson } 146186f8d05fSRichard Henderson if (!is_phys) { 146286f8d05fSRichard Henderson tcg_gen_or_tl(addr, addr, space_select(ctx, sp, base)); 146386f8d05fSRichard Henderson } 146486f8d05fSRichard Henderson *pgva = addr; 146586f8d05fSRichard Henderson #endif 146686f8d05fSRichard Henderson } 146786f8d05fSRichard Henderson 146896d6407fSRichard Henderson /* Emit a memory load. The modify parameter should be 146996d6407fSRichard Henderson * < 0 for pre-modify, 147096d6407fSRichard Henderson * > 0 for post-modify, 147196d6407fSRichard Henderson * = 0 for no base register update. 147296d6407fSRichard Henderson */ 147396d6407fSRichard Henderson static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb, 1474eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 147586f8d05fSRichard Henderson unsigned sp, int modify, TCGMemOp mop) 147696d6407fSRichard Henderson { 147786f8d05fSRichard Henderson TCGv_reg ofs; 147886f8d05fSRichard Henderson TCGv_tl addr; 147996d6407fSRichard Henderson 148096d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 148196d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 148296d6407fSRichard Henderson 148386f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 148486f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 148586f8d05fSRichard Henderson tcg_gen_qemu_ld_reg(dest, addr, ctx->mmu_idx, mop); 148686f8d05fSRichard Henderson if (modify) { 148786f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 148896d6407fSRichard Henderson } 148996d6407fSRichard Henderson } 149096d6407fSRichard Henderson 149196d6407fSRichard Henderson static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb, 1492eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 149386f8d05fSRichard Henderson unsigned sp, int modify, TCGMemOp mop) 149496d6407fSRichard Henderson { 149586f8d05fSRichard Henderson TCGv_reg ofs; 149686f8d05fSRichard Henderson TCGv_tl addr; 149796d6407fSRichard Henderson 149896d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 149996d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 150096d6407fSRichard Henderson 150186f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 150286f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 15033d68ee7bSRichard Henderson tcg_gen_qemu_ld_i64(dest, addr, ctx->mmu_idx, mop); 150486f8d05fSRichard Henderson if (modify) { 150586f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 150696d6407fSRichard Henderson } 150796d6407fSRichard Henderson } 150896d6407fSRichard Henderson 150996d6407fSRichard Henderson static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb, 1510eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 151186f8d05fSRichard Henderson unsigned sp, int modify, TCGMemOp mop) 151296d6407fSRichard Henderson { 151386f8d05fSRichard Henderson TCGv_reg ofs; 151486f8d05fSRichard Henderson TCGv_tl addr; 151596d6407fSRichard Henderson 151696d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 151796d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 151896d6407fSRichard Henderson 151986f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 152086f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 152186f8d05fSRichard Henderson tcg_gen_qemu_st_i32(src, addr, ctx->mmu_idx, mop); 152286f8d05fSRichard Henderson if (modify) { 152386f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 152496d6407fSRichard Henderson } 152596d6407fSRichard Henderson } 152696d6407fSRichard Henderson 152796d6407fSRichard Henderson static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb, 1528eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 152986f8d05fSRichard Henderson unsigned sp, int modify, TCGMemOp mop) 153096d6407fSRichard Henderson { 153186f8d05fSRichard Henderson TCGv_reg ofs; 153286f8d05fSRichard Henderson TCGv_tl addr; 153396d6407fSRichard Henderson 153496d6407fSRichard Henderson /* Caller uses nullify_over/nullify_end. */ 153596d6407fSRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 153696d6407fSRichard Henderson 153786f8d05fSRichard Henderson form_gva(ctx, &addr, &ofs, rb, rx, scale, disp, sp, modify, 153886f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 153986f8d05fSRichard Henderson tcg_gen_qemu_st_i64(src, addr, ctx->mmu_idx, mop); 154086f8d05fSRichard Henderson if (modify) { 154186f8d05fSRichard Henderson save_gpr(ctx, rb, ofs); 154296d6407fSRichard Henderson } 154396d6407fSRichard Henderson } 154496d6407fSRichard Henderson 1545eaa3783bSRichard Henderson #if TARGET_REGISTER_BITS == 64 1546eaa3783bSRichard Henderson #define do_load_reg do_load_64 1547eaa3783bSRichard Henderson #define do_store_reg do_store_64 154896d6407fSRichard Henderson #else 1549eaa3783bSRichard Henderson #define do_load_reg do_load_32 1550eaa3783bSRichard Henderson #define do_store_reg do_store_32 155196d6407fSRichard Henderson #endif 155296d6407fSRichard Henderson 15531cd012a5SRichard Henderson static bool do_load(DisasContext *ctx, unsigned rt, unsigned rb, 1554eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 155586f8d05fSRichard Henderson unsigned sp, int modify, TCGMemOp mop) 155696d6407fSRichard Henderson { 1557eaa3783bSRichard Henderson TCGv_reg dest; 155896d6407fSRichard Henderson 155996d6407fSRichard Henderson nullify_over(ctx); 156096d6407fSRichard Henderson 156196d6407fSRichard Henderson if (modify == 0) { 156296d6407fSRichard Henderson /* No base register update. */ 156396d6407fSRichard Henderson dest = dest_gpr(ctx, rt); 156496d6407fSRichard Henderson } else { 156596d6407fSRichard Henderson /* Make sure if RT == RB, we see the result of the load. */ 156696d6407fSRichard Henderson dest = get_temp(ctx); 156796d6407fSRichard Henderson } 156886f8d05fSRichard Henderson do_load_reg(ctx, dest, rb, rx, scale, disp, sp, modify, mop); 156996d6407fSRichard Henderson save_gpr(ctx, rt, dest); 157096d6407fSRichard Henderson 15711cd012a5SRichard Henderson return nullify_end(ctx); 157296d6407fSRichard Henderson } 157396d6407fSRichard Henderson 157431234768SRichard Henderson static void do_floadw(DisasContext *ctx, unsigned rt, unsigned rb, 1575eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 157686f8d05fSRichard Henderson unsigned sp, int modify) 157796d6407fSRichard Henderson { 157896d6407fSRichard Henderson TCGv_i32 tmp; 157996d6407fSRichard Henderson 158096d6407fSRichard Henderson nullify_over(ctx); 158196d6407fSRichard Henderson 158296d6407fSRichard Henderson tmp = tcg_temp_new_i32(); 158386f8d05fSRichard Henderson do_load_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 158496d6407fSRichard Henderson save_frw_i32(rt, tmp); 158596d6407fSRichard Henderson tcg_temp_free_i32(tmp); 158696d6407fSRichard Henderson 158796d6407fSRichard Henderson if (rt == 0) { 158896d6407fSRichard Henderson gen_helper_loaded_fr0(cpu_env); 158996d6407fSRichard Henderson } 159096d6407fSRichard Henderson 159131234768SRichard Henderson nullify_end(ctx); 159296d6407fSRichard Henderson } 159396d6407fSRichard Henderson 159431234768SRichard Henderson static void do_floadd(DisasContext *ctx, unsigned rt, unsigned rb, 1595eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 159686f8d05fSRichard Henderson unsigned sp, int modify) 159796d6407fSRichard Henderson { 159896d6407fSRichard Henderson TCGv_i64 tmp; 159996d6407fSRichard Henderson 160096d6407fSRichard Henderson nullify_over(ctx); 160196d6407fSRichard Henderson 160296d6407fSRichard Henderson tmp = tcg_temp_new_i64(); 160386f8d05fSRichard Henderson do_load_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEQ); 160496d6407fSRichard Henderson save_frd(rt, tmp); 160596d6407fSRichard Henderson tcg_temp_free_i64(tmp); 160696d6407fSRichard Henderson 160796d6407fSRichard Henderson if (rt == 0) { 160896d6407fSRichard Henderson gen_helper_loaded_fr0(cpu_env); 160996d6407fSRichard Henderson } 161096d6407fSRichard Henderson 161131234768SRichard Henderson nullify_end(ctx); 161296d6407fSRichard Henderson } 161396d6407fSRichard Henderson 16141cd012a5SRichard Henderson static bool do_store(DisasContext *ctx, unsigned rt, unsigned rb, 161586f8d05fSRichard Henderson target_sreg disp, unsigned sp, 161686f8d05fSRichard Henderson int modify, TCGMemOp mop) 161796d6407fSRichard Henderson { 161896d6407fSRichard Henderson nullify_over(ctx); 161986f8d05fSRichard Henderson do_store_reg(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, sp, modify, mop); 16201cd012a5SRichard Henderson return nullify_end(ctx); 162196d6407fSRichard Henderson } 162296d6407fSRichard Henderson 162331234768SRichard Henderson static void do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb, 1624eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 162586f8d05fSRichard Henderson unsigned sp, int modify) 162696d6407fSRichard Henderson { 162796d6407fSRichard Henderson TCGv_i32 tmp; 162896d6407fSRichard Henderson 162996d6407fSRichard Henderson nullify_over(ctx); 163096d6407fSRichard Henderson 163196d6407fSRichard Henderson tmp = load_frw_i32(rt); 163286f8d05fSRichard Henderson do_store_32(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEUL); 163396d6407fSRichard Henderson tcg_temp_free_i32(tmp); 163496d6407fSRichard Henderson 163531234768SRichard Henderson nullify_end(ctx); 163696d6407fSRichard Henderson } 163796d6407fSRichard Henderson 163831234768SRichard Henderson static void do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, 1639eaa3783bSRichard Henderson unsigned rx, int scale, target_sreg disp, 164086f8d05fSRichard Henderson unsigned sp, int modify) 164196d6407fSRichard Henderson { 164296d6407fSRichard Henderson TCGv_i64 tmp; 164396d6407fSRichard Henderson 164496d6407fSRichard Henderson nullify_over(ctx); 164596d6407fSRichard Henderson 164696d6407fSRichard Henderson tmp = load_frd(rt); 164786f8d05fSRichard Henderson do_store_64(ctx, tmp, rb, rx, scale, disp, sp, modify, MO_TEQ); 164896d6407fSRichard Henderson tcg_temp_free_i64(tmp); 164996d6407fSRichard Henderson 165031234768SRichard Henderson nullify_end(ctx); 165196d6407fSRichard Henderson } 165296d6407fSRichard Henderson 165331234768SRichard Henderson static void do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, 1654ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 1655ebe9383cSRichard Henderson { 1656ebe9383cSRichard Henderson TCGv_i32 tmp; 1657ebe9383cSRichard Henderson 1658ebe9383cSRichard Henderson nullify_over(ctx); 1659ebe9383cSRichard Henderson tmp = load_frw0_i32(ra); 1660ebe9383cSRichard Henderson 1661ebe9383cSRichard Henderson func(tmp, cpu_env, tmp); 1662ebe9383cSRichard Henderson 1663ebe9383cSRichard Henderson save_frw_i32(rt, tmp); 1664ebe9383cSRichard Henderson tcg_temp_free_i32(tmp); 166531234768SRichard Henderson nullify_end(ctx); 1666ebe9383cSRichard Henderson } 1667ebe9383cSRichard Henderson 166831234768SRichard Henderson static void do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, 1669ebe9383cSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 1670ebe9383cSRichard Henderson { 1671ebe9383cSRichard Henderson TCGv_i32 dst; 1672ebe9383cSRichard Henderson TCGv_i64 src; 1673ebe9383cSRichard Henderson 1674ebe9383cSRichard Henderson nullify_over(ctx); 1675ebe9383cSRichard Henderson src = load_frd(ra); 1676ebe9383cSRichard Henderson dst = tcg_temp_new_i32(); 1677ebe9383cSRichard Henderson 1678ebe9383cSRichard Henderson func(dst, cpu_env, src); 1679ebe9383cSRichard Henderson 1680ebe9383cSRichard Henderson tcg_temp_free_i64(src); 1681ebe9383cSRichard Henderson save_frw_i32(rt, dst); 1682ebe9383cSRichard Henderson tcg_temp_free_i32(dst); 168331234768SRichard Henderson nullify_end(ctx); 1684ebe9383cSRichard Henderson } 1685ebe9383cSRichard Henderson 168631234768SRichard Henderson static void do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, 1687ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 1688ebe9383cSRichard Henderson { 1689ebe9383cSRichard Henderson TCGv_i64 tmp; 1690ebe9383cSRichard Henderson 1691ebe9383cSRichard Henderson nullify_over(ctx); 1692ebe9383cSRichard Henderson tmp = load_frd0(ra); 1693ebe9383cSRichard Henderson 1694ebe9383cSRichard Henderson func(tmp, cpu_env, tmp); 1695ebe9383cSRichard Henderson 1696ebe9383cSRichard Henderson save_frd(rt, tmp); 1697ebe9383cSRichard Henderson tcg_temp_free_i64(tmp); 169831234768SRichard Henderson nullify_end(ctx); 1699ebe9383cSRichard Henderson } 1700ebe9383cSRichard Henderson 170131234768SRichard Henderson static void do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, 1702ebe9383cSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 1703ebe9383cSRichard Henderson { 1704ebe9383cSRichard Henderson TCGv_i32 src; 1705ebe9383cSRichard Henderson TCGv_i64 dst; 1706ebe9383cSRichard Henderson 1707ebe9383cSRichard Henderson nullify_over(ctx); 1708ebe9383cSRichard Henderson src = load_frw0_i32(ra); 1709ebe9383cSRichard Henderson dst = tcg_temp_new_i64(); 1710ebe9383cSRichard Henderson 1711ebe9383cSRichard Henderson func(dst, cpu_env, src); 1712ebe9383cSRichard Henderson 1713ebe9383cSRichard Henderson tcg_temp_free_i32(src); 1714ebe9383cSRichard Henderson save_frd(rt, dst); 1715ebe9383cSRichard Henderson tcg_temp_free_i64(dst); 171631234768SRichard Henderson nullify_end(ctx); 1717ebe9383cSRichard Henderson } 1718ebe9383cSRichard Henderson 171931234768SRichard Henderson static void do_fop_weww(DisasContext *ctx, unsigned rt, 1720ebe9383cSRichard Henderson unsigned ra, unsigned rb, 172131234768SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 1722ebe9383cSRichard Henderson { 1723ebe9383cSRichard Henderson TCGv_i32 a, b; 1724ebe9383cSRichard Henderson 1725ebe9383cSRichard Henderson nullify_over(ctx); 1726ebe9383cSRichard Henderson a = load_frw0_i32(ra); 1727ebe9383cSRichard Henderson b = load_frw0_i32(rb); 1728ebe9383cSRichard Henderson 1729ebe9383cSRichard Henderson func(a, cpu_env, a, b); 1730ebe9383cSRichard Henderson 1731ebe9383cSRichard Henderson tcg_temp_free_i32(b); 1732ebe9383cSRichard Henderson save_frw_i32(rt, a); 1733ebe9383cSRichard Henderson tcg_temp_free_i32(a); 173431234768SRichard Henderson nullify_end(ctx); 1735ebe9383cSRichard Henderson } 1736ebe9383cSRichard Henderson 173731234768SRichard Henderson static void do_fop_dedd(DisasContext *ctx, unsigned rt, 1738ebe9383cSRichard Henderson unsigned ra, unsigned rb, 173931234768SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 1740ebe9383cSRichard Henderson { 1741ebe9383cSRichard Henderson TCGv_i64 a, b; 1742ebe9383cSRichard Henderson 1743ebe9383cSRichard Henderson nullify_over(ctx); 1744ebe9383cSRichard Henderson a = load_frd0(ra); 1745ebe9383cSRichard Henderson b = load_frd0(rb); 1746ebe9383cSRichard Henderson 1747ebe9383cSRichard Henderson func(a, cpu_env, a, b); 1748ebe9383cSRichard Henderson 1749ebe9383cSRichard Henderson tcg_temp_free_i64(b); 1750ebe9383cSRichard Henderson save_frd(rt, a); 1751ebe9383cSRichard Henderson tcg_temp_free_i64(a); 175231234768SRichard Henderson nullify_end(ctx); 1753ebe9383cSRichard Henderson } 1754ebe9383cSRichard Henderson 175598cd9ca7SRichard Henderson /* Emit an unconditional branch to a direct target, which may or may not 175698cd9ca7SRichard Henderson have already had nullification handled. */ 175701afb7beSRichard Henderson static bool do_dbranch(DisasContext *ctx, target_ureg dest, 175898cd9ca7SRichard Henderson unsigned link, bool is_n) 175998cd9ca7SRichard Henderson { 176098cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) { 176198cd9ca7SRichard Henderson if (link != 0) { 176298cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 176398cd9ca7SRichard Henderson } 176498cd9ca7SRichard Henderson ctx->iaoq_n = dest; 176598cd9ca7SRichard Henderson if (is_n) { 176698cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 176798cd9ca7SRichard Henderson } 176898cd9ca7SRichard Henderson } else { 176998cd9ca7SRichard Henderson nullify_over(ctx); 177098cd9ca7SRichard Henderson 177198cd9ca7SRichard Henderson if (link != 0) { 177298cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 177398cd9ca7SRichard Henderson } 177498cd9ca7SRichard Henderson 177598cd9ca7SRichard Henderson if (is_n && use_nullify_skip(ctx)) { 177698cd9ca7SRichard Henderson nullify_set(ctx, 0); 177798cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, dest, dest + 4); 177898cd9ca7SRichard Henderson } else { 177998cd9ca7SRichard Henderson nullify_set(ctx, is_n); 178098cd9ca7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, dest); 178198cd9ca7SRichard Henderson } 178298cd9ca7SRichard Henderson 178331234768SRichard Henderson nullify_end(ctx); 178498cd9ca7SRichard Henderson 178598cd9ca7SRichard Henderson nullify_set(ctx, 0); 178698cd9ca7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n); 178731234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 178898cd9ca7SRichard Henderson } 178901afb7beSRichard Henderson return true; 179098cd9ca7SRichard Henderson } 179198cd9ca7SRichard Henderson 179298cd9ca7SRichard Henderson /* Emit a conditional branch to a direct target. If the branch itself 179398cd9ca7SRichard Henderson is nullified, we should have already used nullify_over. */ 179401afb7beSRichard Henderson static bool do_cbranch(DisasContext *ctx, target_sreg disp, bool is_n, 179598cd9ca7SRichard Henderson DisasCond *cond) 179698cd9ca7SRichard Henderson { 1797eaa3783bSRichard Henderson target_ureg dest = iaoq_dest(ctx, disp); 179898cd9ca7SRichard Henderson TCGLabel *taken = NULL; 179998cd9ca7SRichard Henderson TCGCond c = cond->c; 180098cd9ca7SRichard Henderson bool n; 180198cd9ca7SRichard Henderson 180298cd9ca7SRichard Henderson assert(ctx->null_cond.c == TCG_COND_NEVER); 180398cd9ca7SRichard Henderson 180498cd9ca7SRichard Henderson /* Handle TRUE and NEVER as direct branches. */ 180598cd9ca7SRichard Henderson if (c == TCG_COND_ALWAYS) { 180601afb7beSRichard Henderson return do_dbranch(ctx, dest, 0, is_n && disp >= 0); 180798cd9ca7SRichard Henderson } 180898cd9ca7SRichard Henderson if (c == TCG_COND_NEVER) { 180901afb7beSRichard Henderson return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0); 181098cd9ca7SRichard Henderson } 181198cd9ca7SRichard Henderson 181298cd9ca7SRichard Henderson taken = gen_new_label(); 181398cd9ca7SRichard Henderson cond_prep(cond); 1814eaa3783bSRichard Henderson tcg_gen_brcond_reg(c, cond->a0, cond->a1, taken); 181598cd9ca7SRichard Henderson cond_free(cond); 181698cd9ca7SRichard Henderson 181798cd9ca7SRichard Henderson /* Not taken: Condition not satisfied; nullify on backward branches. */ 181898cd9ca7SRichard Henderson n = is_n && disp < 0; 181998cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 182098cd9ca7SRichard Henderson nullify_set(ctx, 0); 1821a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_n, ctx->iaoq_n + 4); 182298cd9ca7SRichard Henderson } else { 182398cd9ca7SRichard Henderson if (!n && ctx->null_lab) { 182498cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 182598cd9ca7SRichard Henderson ctx->null_lab = NULL; 182698cd9ca7SRichard Henderson } 182798cd9ca7SRichard Henderson nullify_set(ctx, n); 1828c301f34eSRichard Henderson if (ctx->iaoq_n == -1) { 1829c301f34eSRichard Henderson /* The temporary iaoq_n_var died at the branch above. 1830c301f34eSRichard Henderson Regenerate it here instead of saving it. */ 1831c301f34eSRichard Henderson tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4); 1832c301f34eSRichard Henderson } 1833a881c8e7SRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 183498cd9ca7SRichard Henderson } 183598cd9ca7SRichard Henderson 183698cd9ca7SRichard Henderson gen_set_label(taken); 183798cd9ca7SRichard Henderson 183898cd9ca7SRichard Henderson /* Taken: Condition satisfied; nullify on forward branches. */ 183998cd9ca7SRichard Henderson n = is_n && disp >= 0; 184098cd9ca7SRichard Henderson if (n && use_nullify_skip(ctx)) { 184198cd9ca7SRichard Henderson nullify_set(ctx, 0); 1842a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, dest, dest + 4); 184398cd9ca7SRichard Henderson } else { 184498cd9ca7SRichard Henderson nullify_set(ctx, n); 1845a881c8e7SRichard Henderson gen_goto_tb(ctx, 1, ctx->iaoq_b, dest); 184698cd9ca7SRichard Henderson } 184798cd9ca7SRichard Henderson 184898cd9ca7SRichard Henderson /* Not taken: the branch itself was nullified. */ 184998cd9ca7SRichard Henderson if (ctx->null_lab) { 185098cd9ca7SRichard Henderson gen_set_label(ctx->null_lab); 185198cd9ca7SRichard Henderson ctx->null_lab = NULL; 185231234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 185398cd9ca7SRichard Henderson } else { 185431234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 185598cd9ca7SRichard Henderson } 185601afb7beSRichard Henderson return true; 185798cd9ca7SRichard Henderson } 185898cd9ca7SRichard Henderson 185998cd9ca7SRichard Henderson /* Emit an unconditional branch to an indirect target. This handles 186098cd9ca7SRichard Henderson nullification of the branch itself. */ 186101afb7beSRichard Henderson static bool do_ibranch(DisasContext *ctx, TCGv_reg dest, 186298cd9ca7SRichard Henderson unsigned link, bool is_n) 186398cd9ca7SRichard Henderson { 1864eaa3783bSRichard Henderson TCGv_reg a0, a1, next, tmp; 186598cd9ca7SRichard Henderson TCGCond c; 186698cd9ca7SRichard Henderson 186798cd9ca7SRichard Henderson assert(ctx->null_lab == NULL); 186898cd9ca7SRichard Henderson 186998cd9ca7SRichard Henderson if (ctx->null_cond.c == TCG_COND_NEVER) { 187098cd9ca7SRichard Henderson if (link != 0) { 187198cd9ca7SRichard Henderson copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var); 187298cd9ca7SRichard Henderson } 187398cd9ca7SRichard Henderson next = get_temp(ctx); 1874eaa3783bSRichard Henderson tcg_gen_mov_reg(next, dest); 187598cd9ca7SRichard Henderson if (is_n) { 1876c301f34eSRichard Henderson if (use_nullify_skip(ctx)) { 1877c301f34eSRichard Henderson tcg_gen_mov_reg(cpu_iaoq_f, next); 1878c301f34eSRichard Henderson tcg_gen_addi_reg(cpu_iaoq_b, next, 4); 1879c301f34eSRichard Henderson nullify_set(ctx, 0); 188031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 188101afb7beSRichard Henderson return true; 1882c301f34eSRichard Henderson } 188398cd9ca7SRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 188498cd9ca7SRichard Henderson } 1885c301f34eSRichard Henderson ctx->iaoq_n = -1; 1886c301f34eSRichard Henderson ctx->iaoq_n_var = next; 188798cd9ca7SRichard Henderson } else if (is_n && use_nullify_skip(ctx)) { 188898cd9ca7SRichard Henderson /* The (conditional) branch, B, nullifies the next insn, N, 188998cd9ca7SRichard Henderson and we're allowed to skip execution N (no single-step or 18904137cb83SRichard Henderson tracepoint in effect). Since the goto_ptr that we must use 189198cd9ca7SRichard Henderson for the indirect branch consumes no special resources, we 189298cd9ca7SRichard Henderson can (conditionally) skip B and continue execution. */ 189398cd9ca7SRichard Henderson /* The use_nullify_skip test implies we have a known control path. */ 189498cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_b != -1); 189598cd9ca7SRichard Henderson tcg_debug_assert(ctx->iaoq_n != -1); 189698cd9ca7SRichard Henderson 189798cd9ca7SRichard Henderson /* We do have to handle the non-local temporary, DEST, before 189898cd9ca7SRichard Henderson branching. Since IOAQ_F is not really live at this point, we 189998cd9ca7SRichard Henderson can simply store DEST optimistically. Similarly with IAOQ_B. */ 1900eaa3783bSRichard Henderson tcg_gen_mov_reg(cpu_iaoq_f, dest); 1901eaa3783bSRichard Henderson tcg_gen_addi_reg(cpu_iaoq_b, dest, 4); 190298cd9ca7SRichard Henderson 190398cd9ca7SRichard Henderson nullify_over(ctx); 190498cd9ca7SRichard Henderson if (link != 0) { 1905eaa3783bSRichard Henderson tcg_gen_movi_reg(cpu_gr[link], ctx->iaoq_n); 190698cd9ca7SRichard Henderson } 19077f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 190801afb7beSRichard Henderson return nullify_end(ctx); 190998cd9ca7SRichard Henderson } else { 191098cd9ca7SRichard Henderson cond_prep(&ctx->null_cond); 191198cd9ca7SRichard Henderson c = ctx->null_cond.c; 191298cd9ca7SRichard Henderson a0 = ctx->null_cond.a0; 191398cd9ca7SRichard Henderson a1 = ctx->null_cond.a1; 191498cd9ca7SRichard Henderson 191598cd9ca7SRichard Henderson tmp = tcg_temp_new(); 191698cd9ca7SRichard Henderson next = get_temp(ctx); 191798cd9ca7SRichard Henderson 191898cd9ca7SRichard Henderson copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var); 1919eaa3783bSRichard Henderson tcg_gen_movcond_reg(c, next, a0, a1, tmp, dest); 192098cd9ca7SRichard Henderson ctx->iaoq_n = -1; 192198cd9ca7SRichard Henderson ctx->iaoq_n_var = next; 192298cd9ca7SRichard Henderson 192398cd9ca7SRichard Henderson if (link != 0) { 1924eaa3783bSRichard Henderson tcg_gen_movcond_reg(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp); 192598cd9ca7SRichard Henderson } 192698cd9ca7SRichard Henderson 192798cd9ca7SRichard Henderson if (is_n) { 192898cd9ca7SRichard Henderson /* The branch nullifies the next insn, which means the state of N 192998cd9ca7SRichard Henderson after the branch is the inverse of the state of N that applied 193098cd9ca7SRichard Henderson to the branch. */ 1931eaa3783bSRichard Henderson tcg_gen_setcond_reg(tcg_invert_cond(c), cpu_psw_n, a0, a1); 193298cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 193398cd9ca7SRichard Henderson ctx->null_cond = cond_make_n(); 193498cd9ca7SRichard Henderson ctx->psw_n_nonzero = true; 193598cd9ca7SRichard Henderson } else { 193698cd9ca7SRichard Henderson cond_free(&ctx->null_cond); 193798cd9ca7SRichard Henderson } 193898cd9ca7SRichard Henderson } 193901afb7beSRichard Henderson return true; 194098cd9ca7SRichard Henderson } 194198cd9ca7SRichard Henderson 1942660eefe1SRichard Henderson /* Implement 1943660eefe1SRichard Henderson * if (IAOQ_Front{30..31} < GR[b]{30..31}) 1944660eefe1SRichard Henderson * IAOQ_Next{30..31} ← GR[b]{30..31}; 1945660eefe1SRichard Henderson * else 1946660eefe1SRichard Henderson * IAOQ_Next{30..31} ← IAOQ_Front{30..31}; 1947660eefe1SRichard Henderson * which keeps the privilege level from being increased. 1948660eefe1SRichard Henderson */ 1949660eefe1SRichard Henderson static TCGv_reg do_ibranch_priv(DisasContext *ctx, TCGv_reg offset) 1950660eefe1SRichard Henderson { 1951660eefe1SRichard Henderson TCGv_reg dest; 1952660eefe1SRichard Henderson switch (ctx->privilege) { 1953660eefe1SRichard Henderson case 0: 1954660eefe1SRichard Henderson /* Privilege 0 is maximum and is allowed to decrease. */ 1955660eefe1SRichard Henderson return offset; 1956660eefe1SRichard Henderson case 3: 1957660eefe1SRichard Henderson /* Privilege 3 is minimum and is never allowed increase. */ 1958660eefe1SRichard Henderson dest = get_temp(ctx); 1959660eefe1SRichard Henderson tcg_gen_ori_reg(dest, offset, 3); 1960660eefe1SRichard Henderson break; 1961660eefe1SRichard Henderson default: 1962660eefe1SRichard Henderson dest = tcg_temp_new(); 1963660eefe1SRichard Henderson tcg_gen_andi_reg(dest, offset, -4); 1964660eefe1SRichard Henderson tcg_gen_ori_reg(dest, dest, ctx->privilege); 1965660eefe1SRichard Henderson tcg_gen_movcond_reg(TCG_COND_GTU, dest, dest, offset, dest, offset); 1966660eefe1SRichard Henderson tcg_temp_free(dest); 1967660eefe1SRichard Henderson break; 1968660eefe1SRichard Henderson } 1969660eefe1SRichard Henderson return dest; 1970660eefe1SRichard Henderson } 1971660eefe1SRichard Henderson 1972ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 19737ad439dfSRichard Henderson /* On Linux, page zero is normally marked execute only + gateway. 19747ad439dfSRichard Henderson Therefore normal read or write is supposed to fail, but specific 19757ad439dfSRichard Henderson offsets have kernel code mapped to raise permissions to implement 19767ad439dfSRichard Henderson system calls. Handling this via an explicit check here, rather 19777ad439dfSRichard Henderson in than the "be disp(sr2,r0)" instruction that probably sent us 19787ad439dfSRichard Henderson here, is the easiest way to handle the branch delay slot on the 19797ad439dfSRichard Henderson aforementioned BE. */ 198031234768SRichard Henderson static void do_page_zero(DisasContext *ctx) 19817ad439dfSRichard Henderson { 19827ad439dfSRichard Henderson /* If by some means we get here with PSW[N]=1, that implies that 19837ad439dfSRichard Henderson the B,GATE instruction would be skipped, and we'd fault on the 19847ad439dfSRichard Henderson next insn within the privilaged page. */ 19857ad439dfSRichard Henderson switch (ctx->null_cond.c) { 19867ad439dfSRichard Henderson case TCG_COND_NEVER: 19877ad439dfSRichard Henderson break; 19887ad439dfSRichard Henderson case TCG_COND_ALWAYS: 1989eaa3783bSRichard Henderson tcg_gen_movi_reg(cpu_psw_n, 0); 19907ad439dfSRichard Henderson goto do_sigill; 19917ad439dfSRichard Henderson default: 19927ad439dfSRichard Henderson /* Since this is always the first (and only) insn within the 19937ad439dfSRichard Henderson TB, we should know the state of PSW[N] from TB->FLAGS. */ 19947ad439dfSRichard Henderson g_assert_not_reached(); 19957ad439dfSRichard Henderson } 19967ad439dfSRichard Henderson 19977ad439dfSRichard Henderson /* Check that we didn't arrive here via some means that allowed 19987ad439dfSRichard Henderson non-sequential instruction execution. Normally the PSW[B] bit 19997ad439dfSRichard Henderson detects this by disallowing the B,GATE instruction to execute 20007ad439dfSRichard Henderson under such conditions. */ 20017ad439dfSRichard Henderson if (ctx->iaoq_b != ctx->iaoq_f + 4) { 20027ad439dfSRichard Henderson goto do_sigill; 20037ad439dfSRichard Henderson } 20047ad439dfSRichard Henderson 2005ebd0e151SRichard Henderson switch (ctx->iaoq_f & -4) { 20067ad439dfSRichard Henderson case 0x00: /* Null pointer call */ 20072986721dSRichard Henderson gen_excp_1(EXCP_IMP); 200831234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 200931234768SRichard Henderson break; 20107ad439dfSRichard Henderson 20117ad439dfSRichard Henderson case 0xb0: /* LWS */ 20127ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL_LWS); 201331234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 201431234768SRichard Henderson break; 20157ad439dfSRichard Henderson 20167ad439dfSRichard Henderson case 0xe0: /* SET_THREAD_POINTER */ 201735136a77SRichard Henderson tcg_gen_st_reg(cpu_gr[26], cpu_env, offsetof(CPUHPPAState, cr[27])); 2018ebd0e151SRichard Henderson tcg_gen_ori_reg(cpu_iaoq_f, cpu_gr[31], 3); 2019eaa3783bSRichard Henderson tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4); 202031234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 202131234768SRichard Henderson break; 20227ad439dfSRichard Henderson 20237ad439dfSRichard Henderson case 0x100: /* SYSCALL */ 20247ad439dfSRichard Henderson gen_excp_1(EXCP_SYSCALL); 202531234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 202631234768SRichard Henderson break; 20277ad439dfSRichard Henderson 20287ad439dfSRichard Henderson default: 20297ad439dfSRichard Henderson do_sigill: 20302986721dSRichard Henderson gen_excp_1(EXCP_ILL); 203131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 203231234768SRichard Henderson break; 20337ad439dfSRichard Henderson } 20347ad439dfSRichard Henderson } 2035ba1d0b44SRichard Henderson #endif 20367ad439dfSRichard Henderson 2037deee69a1SRichard Henderson static bool trans_nop(DisasContext *ctx, arg_nop *a) 2038b2167459SRichard Henderson { 2039b2167459SRichard Henderson cond_free(&ctx->null_cond); 204031234768SRichard Henderson return true; 2041b2167459SRichard Henderson } 2042b2167459SRichard Henderson 204340f9f908SRichard Henderson static bool trans_break(DisasContext *ctx, arg_break *a) 204498a9cb79SRichard Henderson { 204531234768SRichard Henderson return gen_excp_iir(ctx, EXCP_BREAK); 204698a9cb79SRichard Henderson } 204798a9cb79SRichard Henderson 2048e36f27efSRichard Henderson static bool trans_sync(DisasContext *ctx, arg_sync *a) 204998a9cb79SRichard Henderson { 205098a9cb79SRichard Henderson /* No point in nullifying the memory barrier. */ 205198a9cb79SRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 205298a9cb79SRichard Henderson 205398a9cb79SRichard Henderson cond_free(&ctx->null_cond); 205431234768SRichard Henderson return true; 205598a9cb79SRichard Henderson } 205698a9cb79SRichard Henderson 2057c603e14aSRichard Henderson static bool trans_mfia(DisasContext *ctx, arg_mfia *a) 205898a9cb79SRichard Henderson { 2059c603e14aSRichard Henderson unsigned rt = a->t; 2060eaa3783bSRichard Henderson TCGv_reg tmp = dest_gpr(ctx, rt); 2061eaa3783bSRichard Henderson tcg_gen_movi_reg(tmp, ctx->iaoq_f); 206298a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 206398a9cb79SRichard Henderson 206498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 206531234768SRichard Henderson return true; 206698a9cb79SRichard Henderson } 206798a9cb79SRichard Henderson 2068c603e14aSRichard Henderson static bool trans_mfsp(DisasContext *ctx, arg_mfsp *a) 206998a9cb79SRichard Henderson { 2070c603e14aSRichard Henderson unsigned rt = a->t; 2071c603e14aSRichard Henderson unsigned rs = a->sp; 207233423472SRichard Henderson TCGv_i64 t0 = tcg_temp_new_i64(); 207333423472SRichard Henderson TCGv_reg t1 = tcg_temp_new(); 207498a9cb79SRichard Henderson 207533423472SRichard Henderson load_spr(ctx, t0, rs); 207633423472SRichard Henderson tcg_gen_shri_i64(t0, t0, 32); 207733423472SRichard Henderson tcg_gen_trunc_i64_reg(t1, t0); 207833423472SRichard Henderson 207933423472SRichard Henderson save_gpr(ctx, rt, t1); 208033423472SRichard Henderson tcg_temp_free(t1); 208133423472SRichard Henderson tcg_temp_free_i64(t0); 208298a9cb79SRichard Henderson 208398a9cb79SRichard Henderson cond_free(&ctx->null_cond); 208431234768SRichard Henderson return true; 208598a9cb79SRichard Henderson } 208698a9cb79SRichard Henderson 2087c603e14aSRichard Henderson static bool trans_mfctl(DisasContext *ctx, arg_mfctl *a) 208898a9cb79SRichard Henderson { 2089c603e14aSRichard Henderson unsigned rt = a->t; 2090c603e14aSRichard Henderson unsigned ctl = a->r; 2091eaa3783bSRichard Henderson TCGv_reg tmp; 209298a9cb79SRichard Henderson 209398a9cb79SRichard Henderson switch (ctl) { 209435136a77SRichard Henderson case CR_SAR: 209598a9cb79SRichard Henderson #ifdef TARGET_HPPA64 2096c603e14aSRichard Henderson if (a->e == 0) { 209798a9cb79SRichard Henderson /* MFSAR without ,W masks low 5 bits. */ 209898a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 2099eaa3783bSRichard Henderson tcg_gen_andi_reg(tmp, cpu_sar, 31); 210098a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 210135136a77SRichard Henderson goto done; 210298a9cb79SRichard Henderson } 210398a9cb79SRichard Henderson #endif 210498a9cb79SRichard Henderson save_gpr(ctx, rt, cpu_sar); 210535136a77SRichard Henderson goto done; 210635136a77SRichard Henderson case CR_IT: /* Interval Timer */ 210735136a77SRichard Henderson /* FIXME: Respect PSW_S bit. */ 210835136a77SRichard Henderson nullify_over(ctx); 210998a9cb79SRichard Henderson tmp = dest_gpr(ctx, rt); 211084b41e65SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { 211149c29d6cSRichard Henderson gen_io_start(); 211249c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 211349c29d6cSRichard Henderson gen_io_end(); 211431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 211549c29d6cSRichard Henderson } else { 211649c29d6cSRichard Henderson gen_helper_read_interval_timer(tmp); 211749c29d6cSRichard Henderson } 211898a9cb79SRichard Henderson save_gpr(ctx, rt, tmp); 211931234768SRichard Henderson return nullify_end(ctx); 212098a9cb79SRichard Henderson case 26: 212198a9cb79SRichard Henderson case 27: 212298a9cb79SRichard Henderson break; 212398a9cb79SRichard Henderson default: 212498a9cb79SRichard Henderson /* All other control registers are privileged. */ 212535136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 212635136a77SRichard Henderson break; 212798a9cb79SRichard Henderson } 212898a9cb79SRichard Henderson 212935136a77SRichard Henderson tmp = get_temp(ctx); 213035136a77SRichard Henderson tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[ctl])); 213135136a77SRichard Henderson save_gpr(ctx, rt, tmp); 213235136a77SRichard Henderson 213335136a77SRichard Henderson done: 213498a9cb79SRichard Henderson cond_free(&ctx->null_cond); 213531234768SRichard Henderson return true; 213698a9cb79SRichard Henderson } 213798a9cb79SRichard Henderson 2138c603e14aSRichard Henderson static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a) 213933423472SRichard Henderson { 2140c603e14aSRichard Henderson unsigned rr = a->r; 2141c603e14aSRichard Henderson unsigned rs = a->sp; 214233423472SRichard Henderson TCGv_i64 t64; 214333423472SRichard Henderson 214433423472SRichard Henderson if (rs >= 5) { 214533423472SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 214633423472SRichard Henderson } 214733423472SRichard Henderson nullify_over(ctx); 214833423472SRichard Henderson 214933423472SRichard Henderson t64 = tcg_temp_new_i64(); 215033423472SRichard Henderson tcg_gen_extu_reg_i64(t64, load_gpr(ctx, rr)); 215133423472SRichard Henderson tcg_gen_shli_i64(t64, t64, 32); 215233423472SRichard Henderson 215333423472SRichard Henderson if (rs >= 4) { 215433423472SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUHPPAState, sr[rs])); 2155494737b7SRichard Henderson ctx->tb_flags &= ~TB_FLAG_SR_SAME; 215633423472SRichard Henderson } else { 215733423472SRichard Henderson tcg_gen_mov_i64(cpu_sr[rs], t64); 215833423472SRichard Henderson } 215933423472SRichard Henderson tcg_temp_free_i64(t64); 216033423472SRichard Henderson 216131234768SRichard Henderson return nullify_end(ctx); 216233423472SRichard Henderson } 216333423472SRichard Henderson 2164c603e14aSRichard Henderson static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a) 216598a9cb79SRichard Henderson { 2166c603e14aSRichard Henderson unsigned ctl = a->t; 2167c603e14aSRichard Henderson TCGv_reg reg = load_gpr(ctx, a->r); 2168eaa3783bSRichard Henderson TCGv_reg tmp; 216998a9cb79SRichard Henderson 217035136a77SRichard Henderson if (ctl == CR_SAR) { 217198a9cb79SRichard Henderson tmp = tcg_temp_new(); 217235136a77SRichard Henderson tcg_gen_andi_reg(tmp, reg, TARGET_REGISTER_BITS - 1); 217398a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 217498a9cb79SRichard Henderson tcg_temp_free(tmp); 217598a9cb79SRichard Henderson 217698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 217731234768SRichard Henderson return true; 217898a9cb79SRichard Henderson } 217998a9cb79SRichard Henderson 218035136a77SRichard Henderson /* All other control registers are privileged or read-only. */ 218135136a77SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_REG); 218235136a77SRichard Henderson 2183c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 218435136a77SRichard Henderson nullify_over(ctx); 218535136a77SRichard Henderson switch (ctl) { 218635136a77SRichard Henderson case CR_IT: 218749c29d6cSRichard Henderson gen_helper_write_interval_timer(cpu_env, reg); 218835136a77SRichard Henderson break; 21894f5f2548SRichard Henderson case CR_EIRR: 21904f5f2548SRichard Henderson gen_helper_write_eirr(cpu_env, reg); 21914f5f2548SRichard Henderson break; 21924f5f2548SRichard Henderson case CR_EIEM: 21934f5f2548SRichard Henderson gen_helper_write_eiem(cpu_env, reg); 219431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 21954f5f2548SRichard Henderson break; 21964f5f2548SRichard Henderson 219735136a77SRichard Henderson case CR_IIASQ: 219835136a77SRichard Henderson case CR_IIAOQ: 219935136a77SRichard Henderson /* FIXME: Respect PSW_Q bit */ 220035136a77SRichard Henderson /* The write advances the queue and stores to the back element. */ 220135136a77SRichard Henderson tmp = get_temp(ctx); 220235136a77SRichard Henderson tcg_gen_ld_reg(tmp, cpu_env, 220335136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 220435136a77SRichard Henderson tcg_gen_st_reg(tmp, cpu_env, offsetof(CPUHPPAState, cr[ctl])); 220535136a77SRichard Henderson tcg_gen_st_reg(reg, cpu_env, 220635136a77SRichard Henderson offsetof(CPUHPPAState, cr_back[ctl - CR_IIASQ])); 220735136a77SRichard Henderson break; 220835136a77SRichard Henderson 220935136a77SRichard Henderson default: 221035136a77SRichard Henderson tcg_gen_st_reg(reg, cpu_env, offsetof(CPUHPPAState, cr[ctl])); 221135136a77SRichard Henderson break; 221235136a77SRichard Henderson } 221331234768SRichard Henderson return nullify_end(ctx); 22144f5f2548SRichard Henderson #endif 221535136a77SRichard Henderson } 221635136a77SRichard Henderson 2217c603e14aSRichard Henderson static bool trans_mtsarcm(DisasContext *ctx, arg_mtsarcm *a) 221898a9cb79SRichard Henderson { 2219eaa3783bSRichard Henderson TCGv_reg tmp = tcg_temp_new(); 222098a9cb79SRichard Henderson 2221c603e14aSRichard Henderson tcg_gen_not_reg(tmp, load_gpr(ctx, a->r)); 2222eaa3783bSRichard Henderson tcg_gen_andi_reg(tmp, tmp, TARGET_REGISTER_BITS - 1); 222398a9cb79SRichard Henderson save_or_nullify(ctx, cpu_sar, tmp); 222498a9cb79SRichard Henderson tcg_temp_free(tmp); 222598a9cb79SRichard Henderson 222698a9cb79SRichard Henderson cond_free(&ctx->null_cond); 222731234768SRichard Henderson return true; 222898a9cb79SRichard Henderson } 222998a9cb79SRichard Henderson 2230e36f27efSRichard Henderson static bool trans_ldsid(DisasContext *ctx, arg_ldsid *a) 223198a9cb79SRichard Henderson { 2232e36f27efSRichard Henderson TCGv_reg dest = dest_gpr(ctx, a->t); 223398a9cb79SRichard Henderson 22342330504cSHelge Deller #ifdef CONFIG_USER_ONLY 22352330504cSHelge Deller /* We don't implement space registers in user mode. */ 2236eaa3783bSRichard Henderson tcg_gen_movi_reg(dest, 0); 22372330504cSHelge Deller #else 22382330504cSHelge Deller TCGv_i64 t0 = tcg_temp_new_i64(); 22392330504cSHelge Deller 2240e36f27efSRichard Henderson tcg_gen_mov_i64(t0, space_select(ctx, a->sp, load_gpr(ctx, a->b))); 22412330504cSHelge Deller tcg_gen_shri_i64(t0, t0, 32); 22422330504cSHelge Deller tcg_gen_trunc_i64_reg(dest, t0); 22432330504cSHelge Deller 22442330504cSHelge Deller tcg_temp_free_i64(t0); 22452330504cSHelge Deller #endif 2246e36f27efSRichard Henderson save_gpr(ctx, a->t, dest); 224798a9cb79SRichard Henderson 224898a9cb79SRichard Henderson cond_free(&ctx->null_cond); 224931234768SRichard Henderson return true; 225098a9cb79SRichard Henderson } 225198a9cb79SRichard Henderson 2252e36f27efSRichard Henderson static bool trans_rsm(DisasContext *ctx, arg_rsm *a) 2253e36f27efSRichard Henderson { 2254e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2255e1b5a5edSRichard Henderson #ifndef CONFIG_USER_ONLY 2256e1b5a5edSRichard Henderson TCGv_reg tmp; 2257e1b5a5edSRichard Henderson 2258e1b5a5edSRichard Henderson nullify_over(ctx); 2259e1b5a5edSRichard Henderson 2260e1b5a5edSRichard Henderson tmp = get_temp(ctx); 2261e1b5a5edSRichard Henderson tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, psw)); 2262e36f27efSRichard Henderson tcg_gen_andi_reg(tmp, tmp, ~a->i); 2263e1b5a5edSRichard Henderson gen_helper_swap_system_mask(tmp, cpu_env, tmp); 2264e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2265e1b5a5edSRichard Henderson 2266e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_M. */ 226731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 226831234768SRichard Henderson return nullify_end(ctx); 2269e36f27efSRichard Henderson #endif 2270e1b5a5edSRichard Henderson } 2271e1b5a5edSRichard Henderson 2272e36f27efSRichard Henderson static bool trans_ssm(DisasContext *ctx, arg_ssm *a) 2273e1b5a5edSRichard Henderson { 2274e36f27efSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2275e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2276e1b5a5edSRichard Henderson TCGv_reg tmp; 2277e1b5a5edSRichard Henderson 2278e1b5a5edSRichard Henderson nullify_over(ctx); 2279e1b5a5edSRichard Henderson 2280e1b5a5edSRichard Henderson tmp = get_temp(ctx); 2281e1b5a5edSRichard Henderson tcg_gen_ld_reg(tmp, cpu_env, offsetof(CPUHPPAState, psw)); 2282e36f27efSRichard Henderson tcg_gen_ori_reg(tmp, tmp, a->i); 2283e1b5a5edSRichard Henderson gen_helper_swap_system_mask(tmp, cpu_env, tmp); 2284e36f27efSRichard Henderson save_gpr(ctx, a->t, tmp); 2285e1b5a5edSRichard Henderson 2286e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts, e.g. PSW_I. */ 228731234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 228831234768SRichard Henderson return nullify_end(ctx); 2289e36f27efSRichard Henderson #endif 2290e1b5a5edSRichard Henderson } 2291e1b5a5edSRichard Henderson 2292c603e14aSRichard Henderson static bool trans_mtsm(DisasContext *ctx, arg_mtsm *a) 2293e1b5a5edSRichard Henderson { 2294e1b5a5edSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2295c603e14aSRichard Henderson #ifndef CONFIG_USER_ONLY 2296c603e14aSRichard Henderson TCGv_reg tmp, reg; 2297e1b5a5edSRichard Henderson nullify_over(ctx); 2298e1b5a5edSRichard Henderson 2299c603e14aSRichard Henderson reg = load_gpr(ctx, a->r); 2300e1b5a5edSRichard Henderson tmp = get_temp(ctx); 2301e1b5a5edSRichard Henderson gen_helper_swap_system_mask(tmp, cpu_env, reg); 2302e1b5a5edSRichard Henderson 2303e1b5a5edSRichard Henderson /* Exit the TB to recognize new interrupts. */ 230431234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE_EXIT; 230531234768SRichard Henderson return nullify_end(ctx); 2306c603e14aSRichard Henderson #endif 2307e1b5a5edSRichard Henderson } 2308f49b3537SRichard Henderson 2309e36f27efSRichard Henderson static bool do_rfi(DisasContext *ctx, bool rfi_r) 2310f49b3537SRichard Henderson { 2311f49b3537SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2312e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 2313f49b3537SRichard Henderson nullify_over(ctx); 2314f49b3537SRichard Henderson 2315e36f27efSRichard Henderson if (rfi_r) { 2316f49b3537SRichard Henderson gen_helper_rfi_r(cpu_env); 2317f49b3537SRichard Henderson } else { 2318f49b3537SRichard Henderson gen_helper_rfi(cpu_env); 2319f49b3537SRichard Henderson } 232031234768SRichard Henderson /* Exit the TB to recognize new interrupts. */ 2321f49b3537SRichard Henderson if (ctx->base.singlestep_enabled) { 2322f49b3537SRichard Henderson gen_excp_1(EXCP_DEBUG); 2323f49b3537SRichard Henderson } else { 232407ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 2325f49b3537SRichard Henderson } 232631234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2327f49b3537SRichard Henderson 232831234768SRichard Henderson return nullify_end(ctx); 2329e36f27efSRichard Henderson #endif 2330f49b3537SRichard Henderson } 23316210db05SHelge Deller 2332e36f27efSRichard Henderson static bool trans_rfi(DisasContext *ctx, arg_rfi *a) 2333e36f27efSRichard Henderson { 2334e36f27efSRichard Henderson return do_rfi(ctx, false); 2335e36f27efSRichard Henderson } 2336e36f27efSRichard Henderson 2337e36f27efSRichard Henderson static bool trans_rfi_r(DisasContext *ctx, arg_rfi_r *a) 2338e36f27efSRichard Henderson { 2339e36f27efSRichard Henderson return do_rfi(ctx, true); 2340e36f27efSRichard Henderson } 2341e36f27efSRichard Henderson 2342e36f27efSRichard Henderson #ifndef CONFIG_USER_ONLY 234331234768SRichard Henderson static bool gen_hlt(DisasContext *ctx, int reset) 23446210db05SHelge Deller { 23456210db05SHelge Deller CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 23466210db05SHelge Deller nullify_over(ctx); 23476210db05SHelge Deller if (reset) { 23486210db05SHelge Deller gen_helper_reset(cpu_env); 23496210db05SHelge Deller } else { 23506210db05SHelge Deller gen_helper_halt(cpu_env); 23516210db05SHelge Deller } 235231234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 235331234768SRichard Henderson return nullify_end(ctx); 23546210db05SHelge Deller } 2355e1b5a5edSRichard Henderson #endif /* !CONFIG_USER_ONLY */ 2356e1b5a5edSRichard Henderson 2357deee69a1SRichard Henderson static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a) 235898a9cb79SRichard Henderson { 2359deee69a1SRichard Henderson if (a->m) { 2360deee69a1SRichard Henderson TCGv_reg dest = dest_gpr(ctx, a->b); 2361deee69a1SRichard Henderson TCGv_reg src1 = load_gpr(ctx, a->b); 2362deee69a1SRichard Henderson TCGv_reg src2 = load_gpr(ctx, a->x); 236398a9cb79SRichard Henderson 236498a9cb79SRichard Henderson /* The only thing we need to do is the base register modification. */ 2365eaa3783bSRichard Henderson tcg_gen_add_reg(dest, src1, src2); 2366deee69a1SRichard Henderson save_gpr(ctx, a->b, dest); 2367deee69a1SRichard Henderson } 236898a9cb79SRichard Henderson cond_free(&ctx->null_cond); 236931234768SRichard Henderson return true; 237098a9cb79SRichard Henderson } 237198a9cb79SRichard Henderson 2372deee69a1SRichard Henderson static bool trans_probe(DisasContext *ctx, arg_probe *a) 237398a9cb79SRichard Henderson { 237486f8d05fSRichard Henderson TCGv_reg dest, ofs; 2375eed14219SRichard Henderson TCGv_i32 level, want; 237686f8d05fSRichard Henderson TCGv_tl addr; 237798a9cb79SRichard Henderson 237898a9cb79SRichard Henderson nullify_over(ctx); 237998a9cb79SRichard Henderson 2380deee69a1SRichard Henderson dest = dest_gpr(ctx, a->t); 2381deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2382eed14219SRichard Henderson 2383deee69a1SRichard Henderson if (a->imm) { 2384deee69a1SRichard Henderson level = tcg_const_i32(a->ri); 238598a9cb79SRichard Henderson } else { 2386eed14219SRichard Henderson level = tcg_temp_new_i32(); 2387deee69a1SRichard Henderson tcg_gen_trunc_reg_i32(level, load_gpr(ctx, a->ri)); 2388eed14219SRichard Henderson tcg_gen_andi_i32(level, level, 3); 238998a9cb79SRichard Henderson } 2390deee69a1SRichard Henderson want = tcg_const_i32(a->write ? PAGE_WRITE : PAGE_READ); 2391eed14219SRichard Henderson 2392eed14219SRichard Henderson gen_helper_probe(dest, cpu_env, addr, level, want); 2393eed14219SRichard Henderson 2394eed14219SRichard Henderson tcg_temp_free_i32(want); 2395eed14219SRichard Henderson tcg_temp_free_i32(level); 2396eed14219SRichard Henderson 2397deee69a1SRichard Henderson save_gpr(ctx, a->t, dest); 239831234768SRichard Henderson return nullify_end(ctx); 239998a9cb79SRichard Henderson } 240098a9cb79SRichard Henderson 2401deee69a1SRichard Henderson static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a) 24028d6ae7fbSRichard Henderson { 2403deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2404deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24058d6ae7fbSRichard Henderson TCGv_tl addr; 24068d6ae7fbSRichard Henderson TCGv_reg ofs, reg; 24078d6ae7fbSRichard Henderson 24088d6ae7fbSRichard Henderson nullify_over(ctx); 24098d6ae7fbSRichard Henderson 2410deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false); 2411deee69a1SRichard Henderson reg = load_gpr(ctx, a->r); 2412deee69a1SRichard Henderson if (a->addr) { 24138d6ae7fbSRichard Henderson gen_helper_itlba(cpu_env, addr, reg); 24148d6ae7fbSRichard Henderson } else { 24158d6ae7fbSRichard Henderson gen_helper_itlbp(cpu_env, addr, reg); 24168d6ae7fbSRichard Henderson } 24178d6ae7fbSRichard Henderson 24188d6ae7fbSRichard Henderson /* Exit TB for ITLB change if mmu is enabled. This *should* not be 24198d6ae7fbSRichard Henderson the case, since the OS TLB fill handler runs with mmu disabled. */ 2420deee69a1SRichard Henderson if (!a->data && (ctx->tb_flags & PSW_C)) { 242131234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 242231234768SRichard Henderson } 242331234768SRichard Henderson return nullify_end(ctx); 2424deee69a1SRichard Henderson #endif 24258d6ae7fbSRichard Henderson } 242663300a00SRichard Henderson 2427deee69a1SRichard Henderson static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a) 242863300a00SRichard Henderson { 2429deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2430deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 243163300a00SRichard Henderson TCGv_tl addr; 243263300a00SRichard Henderson TCGv_reg ofs; 243363300a00SRichard Henderson 243463300a00SRichard Henderson nullify_over(ctx); 243563300a00SRichard Henderson 2436deee69a1SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 2437deee69a1SRichard Henderson if (a->m) { 2438deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 243963300a00SRichard Henderson } 2440deee69a1SRichard Henderson if (a->local) { 244163300a00SRichard Henderson gen_helper_ptlbe(cpu_env); 244263300a00SRichard Henderson } else { 244363300a00SRichard Henderson gen_helper_ptlb(cpu_env, addr); 244463300a00SRichard Henderson } 244563300a00SRichard Henderson 244663300a00SRichard Henderson /* Exit TB for TLB change if mmu is enabled. */ 2447deee69a1SRichard Henderson if (!a->data && (ctx->tb_flags & PSW_C)) { 244831234768SRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_STALE; 244931234768SRichard Henderson } 245031234768SRichard Henderson return nullify_end(ctx); 2451deee69a1SRichard Henderson #endif 245263300a00SRichard Henderson } 24532dfcca9fSRichard Henderson 2454deee69a1SRichard Henderson static bool trans_lpa(DisasContext *ctx, arg_ldst *a) 24552dfcca9fSRichard Henderson { 2456deee69a1SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2457deee69a1SRichard Henderson #ifndef CONFIG_USER_ONLY 24582dfcca9fSRichard Henderson TCGv_tl vaddr; 24592dfcca9fSRichard Henderson TCGv_reg ofs, paddr; 24602dfcca9fSRichard Henderson 24612dfcca9fSRichard Henderson nullify_over(ctx); 24622dfcca9fSRichard Henderson 2463deee69a1SRichard Henderson form_gva(ctx, &vaddr, &ofs, a->b, a->x, 0, 0, a->sp, a->m, false); 24642dfcca9fSRichard Henderson 24652dfcca9fSRichard Henderson paddr = tcg_temp_new(); 24662dfcca9fSRichard Henderson gen_helper_lpa(paddr, cpu_env, vaddr); 24672dfcca9fSRichard Henderson 24682dfcca9fSRichard Henderson /* Note that physical address result overrides base modification. */ 2469deee69a1SRichard Henderson if (a->m) { 2470deee69a1SRichard Henderson save_gpr(ctx, a->b, ofs); 24712dfcca9fSRichard Henderson } 2472deee69a1SRichard Henderson save_gpr(ctx, a->t, paddr); 24732dfcca9fSRichard Henderson tcg_temp_free(paddr); 24742dfcca9fSRichard Henderson 247531234768SRichard Henderson return nullify_end(ctx); 2476deee69a1SRichard Henderson #endif 24772dfcca9fSRichard Henderson } 247843a97b81SRichard Henderson 2479deee69a1SRichard Henderson static bool trans_lci(DisasContext *ctx, arg_lci *a) 248043a97b81SRichard Henderson { 248143a97b81SRichard Henderson TCGv_reg ci; 248243a97b81SRichard Henderson 248343a97b81SRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 248443a97b81SRichard Henderson 248543a97b81SRichard Henderson /* The Coherence Index is an implementation-defined function of the 248643a97b81SRichard Henderson physical address. Two addresses with the same CI have a coherent 248743a97b81SRichard Henderson view of the cache. Our implementation is to return 0 for all, 248843a97b81SRichard Henderson since the entire address space is coherent. */ 248943a97b81SRichard Henderson ci = tcg_const_reg(0); 2490deee69a1SRichard Henderson save_gpr(ctx, a->t, ci); 249143a97b81SRichard Henderson tcg_temp_free(ci); 249243a97b81SRichard Henderson 249331234768SRichard Henderson cond_free(&ctx->null_cond); 249431234768SRichard Henderson return true; 249543a97b81SRichard Henderson } 249698a9cb79SRichard Henderson 24970c982a28SRichard Henderson static bool trans_add(DisasContext *ctx, arg_rrr_cf_sh *a) 2498b2167459SRichard Henderson { 24990c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, false); 2500b2167459SRichard Henderson } 2501b2167459SRichard Henderson 25020c982a28SRichard Henderson static bool trans_add_l(DisasContext *ctx, arg_rrr_cf_sh *a) 2503b2167459SRichard Henderson { 25040c982a28SRichard Henderson return do_add_reg(ctx, a, true, false, false, false); 2505b2167459SRichard Henderson } 2506b2167459SRichard Henderson 25070c982a28SRichard Henderson static bool trans_add_tsv(DisasContext *ctx, arg_rrr_cf_sh *a) 2508b2167459SRichard Henderson { 25090c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, false); 2510b2167459SRichard Henderson } 2511b2167459SRichard Henderson 25120c982a28SRichard Henderson static bool trans_add_c(DisasContext *ctx, arg_rrr_cf_sh *a) 2513b2167459SRichard Henderson { 25140c982a28SRichard Henderson return do_add_reg(ctx, a, false, false, false, true); 25150c982a28SRichard Henderson } 2516b2167459SRichard Henderson 25170c982a28SRichard Henderson static bool trans_add_c_tsv(DisasContext *ctx, arg_rrr_cf_sh *a) 25180c982a28SRichard Henderson { 25190c982a28SRichard Henderson return do_add_reg(ctx, a, false, true, false, true); 25200c982a28SRichard Henderson } 25210c982a28SRichard Henderson 25220c982a28SRichard Henderson static bool trans_sub(DisasContext *ctx, arg_rrr_cf *a) 25230c982a28SRichard Henderson { 25240c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, false); 25250c982a28SRichard Henderson } 25260c982a28SRichard Henderson 25270c982a28SRichard Henderson static bool trans_sub_tsv(DisasContext *ctx, arg_rrr_cf *a) 25280c982a28SRichard Henderson { 25290c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, false); 25300c982a28SRichard Henderson } 25310c982a28SRichard Henderson 25320c982a28SRichard Henderson static bool trans_sub_tc(DisasContext *ctx, arg_rrr_cf *a) 25330c982a28SRichard Henderson { 25340c982a28SRichard Henderson return do_sub_reg(ctx, a, false, false, true); 25350c982a28SRichard Henderson } 25360c982a28SRichard Henderson 25370c982a28SRichard Henderson static bool trans_sub_tsv_tc(DisasContext *ctx, arg_rrr_cf *a) 25380c982a28SRichard Henderson { 25390c982a28SRichard Henderson return do_sub_reg(ctx, a, true, false, true); 25400c982a28SRichard Henderson } 25410c982a28SRichard Henderson 25420c982a28SRichard Henderson static bool trans_sub_b(DisasContext *ctx, arg_rrr_cf *a) 25430c982a28SRichard Henderson { 25440c982a28SRichard Henderson return do_sub_reg(ctx, a, false, true, false); 25450c982a28SRichard Henderson } 25460c982a28SRichard Henderson 25470c982a28SRichard Henderson static bool trans_sub_b_tsv(DisasContext *ctx, arg_rrr_cf *a) 25480c982a28SRichard Henderson { 25490c982a28SRichard Henderson return do_sub_reg(ctx, a, true, true, false); 25500c982a28SRichard Henderson } 25510c982a28SRichard Henderson 25520c982a28SRichard Henderson static bool trans_andcm(DisasContext *ctx, arg_rrr_cf *a) 25530c982a28SRichard Henderson { 25540c982a28SRichard Henderson return do_log_reg(ctx, a, tcg_gen_andc_reg); 25550c982a28SRichard Henderson } 25560c982a28SRichard Henderson 25570c982a28SRichard Henderson static bool trans_and(DisasContext *ctx, arg_rrr_cf *a) 25580c982a28SRichard Henderson { 25590c982a28SRichard Henderson return do_log_reg(ctx, a, tcg_gen_and_reg); 25600c982a28SRichard Henderson } 25610c982a28SRichard Henderson 25620c982a28SRichard Henderson static bool trans_or(DisasContext *ctx, arg_rrr_cf *a) 25630c982a28SRichard Henderson { 25640c982a28SRichard Henderson if (a->cf == 0) { 25650c982a28SRichard Henderson unsigned r2 = a->r2; 25660c982a28SRichard Henderson unsigned r1 = a->r1; 25670c982a28SRichard Henderson unsigned rt = a->t; 25680c982a28SRichard Henderson 25697aee8189SRichard Henderson if (rt == 0) { /* NOP */ 25707aee8189SRichard Henderson cond_free(&ctx->null_cond); 25717aee8189SRichard Henderson return true; 25727aee8189SRichard Henderson } 25737aee8189SRichard Henderson if (r2 == 0) { /* COPY */ 2574b2167459SRichard Henderson if (r1 == 0) { 2575eaa3783bSRichard Henderson TCGv_reg dest = dest_gpr(ctx, rt); 2576eaa3783bSRichard Henderson tcg_gen_movi_reg(dest, 0); 2577b2167459SRichard Henderson save_gpr(ctx, rt, dest); 2578b2167459SRichard Henderson } else { 2579b2167459SRichard Henderson save_gpr(ctx, rt, cpu_gr[r1]); 2580b2167459SRichard Henderson } 2581b2167459SRichard Henderson cond_free(&ctx->null_cond); 258231234768SRichard Henderson return true; 2583b2167459SRichard Henderson } 25847aee8189SRichard Henderson #ifndef CONFIG_USER_ONLY 25857aee8189SRichard Henderson /* These are QEMU extensions and are nops in the real architecture: 25867aee8189SRichard Henderson * 25877aee8189SRichard Henderson * or %r10,%r10,%r10 -- idle loop; wait for interrupt 25887aee8189SRichard Henderson * or %r31,%r31,%r31 -- death loop; offline cpu 25897aee8189SRichard Henderson * currently implemented as idle. 25907aee8189SRichard Henderson */ 25917aee8189SRichard Henderson if ((rt == 10 || rt == 31) && r1 == rt && r2 == rt) { /* PAUSE */ 25927aee8189SRichard Henderson TCGv_i32 tmp; 25937aee8189SRichard Henderson 25947aee8189SRichard Henderson /* No need to check for supervisor, as userland can only pause 25957aee8189SRichard Henderson until the next timer interrupt. */ 25967aee8189SRichard Henderson nullify_over(ctx); 25977aee8189SRichard Henderson 25987aee8189SRichard Henderson /* Advance the instruction queue. */ 25997aee8189SRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 26007aee8189SRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 26017aee8189SRichard Henderson nullify_set(ctx, 0); 26027aee8189SRichard Henderson 26037aee8189SRichard Henderson /* Tell the qemu main loop to halt until this cpu has work. */ 26047aee8189SRichard Henderson tmp = tcg_const_i32(1); 26057aee8189SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, -offsetof(HPPACPU, env) + 26067aee8189SRichard Henderson offsetof(CPUState, halted)); 26077aee8189SRichard Henderson tcg_temp_free_i32(tmp); 26087aee8189SRichard Henderson gen_excp_1(EXCP_HALTED); 26097aee8189SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 26107aee8189SRichard Henderson 26117aee8189SRichard Henderson return nullify_end(ctx); 26127aee8189SRichard Henderson } 26137aee8189SRichard Henderson #endif 26147aee8189SRichard Henderson } 26150c982a28SRichard Henderson return do_log_reg(ctx, a, tcg_gen_or_reg); 26167aee8189SRichard Henderson } 2617b2167459SRichard Henderson 26180c982a28SRichard Henderson static bool trans_xor(DisasContext *ctx, arg_rrr_cf *a) 2619b2167459SRichard Henderson { 26200c982a28SRichard Henderson return do_log_reg(ctx, a, tcg_gen_xor_reg); 26210c982a28SRichard Henderson } 26220c982a28SRichard Henderson 26230c982a28SRichard Henderson static bool trans_cmpclr(DisasContext *ctx, arg_rrr_cf *a) 26240c982a28SRichard Henderson { 2625eaa3783bSRichard Henderson TCGv_reg tcg_r1, tcg_r2; 2626b2167459SRichard Henderson 26270c982a28SRichard Henderson if (a->cf) { 2628b2167459SRichard Henderson nullify_over(ctx); 2629b2167459SRichard Henderson } 26300c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26310c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 26320c982a28SRichard Henderson do_cmpclr(ctx, a->t, tcg_r1, tcg_r2, a->cf); 263331234768SRichard Henderson return nullify_end(ctx); 2634b2167459SRichard Henderson } 2635b2167459SRichard Henderson 26360c982a28SRichard Henderson static bool trans_uxor(DisasContext *ctx, arg_rrr_cf *a) 2637b2167459SRichard Henderson { 2638eaa3783bSRichard Henderson TCGv_reg tcg_r1, tcg_r2; 2639b2167459SRichard Henderson 26400c982a28SRichard Henderson if (a->cf) { 2641b2167459SRichard Henderson nullify_over(ctx); 2642b2167459SRichard Henderson } 26430c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26440c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 26450c982a28SRichard Henderson do_unit(ctx, a->t, tcg_r1, tcg_r2, a->cf, false, tcg_gen_xor_reg); 264631234768SRichard Henderson return nullify_end(ctx); 2647b2167459SRichard Henderson } 2648b2167459SRichard Henderson 26490c982a28SRichard Henderson static bool do_uaddcm(DisasContext *ctx, arg_rrr_cf *a, bool is_tc) 2650b2167459SRichard Henderson { 2651eaa3783bSRichard Henderson TCGv_reg tcg_r1, tcg_r2, tmp; 2652b2167459SRichard Henderson 26530c982a28SRichard Henderson if (a->cf) { 2654b2167459SRichard Henderson nullify_over(ctx); 2655b2167459SRichard Henderson } 26560c982a28SRichard Henderson tcg_r1 = load_gpr(ctx, a->r1); 26570c982a28SRichard Henderson tcg_r2 = load_gpr(ctx, a->r2); 2658b2167459SRichard Henderson tmp = get_temp(ctx); 2659eaa3783bSRichard Henderson tcg_gen_not_reg(tmp, tcg_r2); 26600c982a28SRichard Henderson do_unit(ctx, a->t, tcg_r1, tmp, a->cf, is_tc, tcg_gen_add_reg); 266131234768SRichard Henderson return nullify_end(ctx); 2662b2167459SRichard Henderson } 2663b2167459SRichard Henderson 26640c982a28SRichard Henderson static bool trans_uaddcm(DisasContext *ctx, arg_rrr_cf *a) 2665b2167459SRichard Henderson { 26660c982a28SRichard Henderson return do_uaddcm(ctx, a, false); 26670c982a28SRichard Henderson } 26680c982a28SRichard Henderson 26690c982a28SRichard Henderson static bool trans_uaddcm_tc(DisasContext *ctx, arg_rrr_cf *a) 26700c982a28SRichard Henderson { 26710c982a28SRichard Henderson return do_uaddcm(ctx, a, true); 26720c982a28SRichard Henderson } 26730c982a28SRichard Henderson 26740c982a28SRichard Henderson static bool do_dcor(DisasContext *ctx, arg_rr_cf *a, bool is_i) 26750c982a28SRichard Henderson { 2676eaa3783bSRichard Henderson TCGv_reg tmp; 2677b2167459SRichard Henderson 2678b2167459SRichard Henderson nullify_over(ctx); 2679b2167459SRichard Henderson 2680b2167459SRichard Henderson tmp = get_temp(ctx); 2681eaa3783bSRichard Henderson tcg_gen_shri_reg(tmp, cpu_psw_cb, 3); 2682b2167459SRichard Henderson if (!is_i) { 2683eaa3783bSRichard Henderson tcg_gen_not_reg(tmp, tmp); 2684b2167459SRichard Henderson } 2685eaa3783bSRichard Henderson tcg_gen_andi_reg(tmp, tmp, 0x11111111); 2686eaa3783bSRichard Henderson tcg_gen_muli_reg(tmp, tmp, 6); 26870c982a28SRichard Henderson do_unit(ctx, a->t, tmp, load_gpr(ctx, a->r), a->cf, false, 2688eaa3783bSRichard Henderson is_i ? tcg_gen_add_reg : tcg_gen_sub_reg); 268931234768SRichard Henderson return nullify_end(ctx); 2690b2167459SRichard Henderson } 2691b2167459SRichard Henderson 26920c982a28SRichard Henderson static bool trans_dcor(DisasContext *ctx, arg_rr_cf *a) 2693b2167459SRichard Henderson { 26940c982a28SRichard Henderson return do_dcor(ctx, a, false); 26950c982a28SRichard Henderson } 26960c982a28SRichard Henderson 26970c982a28SRichard Henderson static bool trans_dcor_i(DisasContext *ctx, arg_rr_cf *a) 26980c982a28SRichard Henderson { 26990c982a28SRichard Henderson return do_dcor(ctx, a, true); 27000c982a28SRichard Henderson } 27010c982a28SRichard Henderson 27020c982a28SRichard Henderson static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) 27030c982a28SRichard Henderson { 2704eaa3783bSRichard Henderson TCGv_reg dest, add1, add2, addc, zero, in1, in2; 2705b2167459SRichard Henderson 2706b2167459SRichard Henderson nullify_over(ctx); 2707b2167459SRichard Henderson 27080c982a28SRichard Henderson in1 = load_gpr(ctx, a->r1); 27090c982a28SRichard Henderson in2 = load_gpr(ctx, a->r2); 2710b2167459SRichard Henderson 2711b2167459SRichard Henderson add1 = tcg_temp_new(); 2712b2167459SRichard Henderson add2 = tcg_temp_new(); 2713b2167459SRichard Henderson addc = tcg_temp_new(); 2714b2167459SRichard Henderson dest = tcg_temp_new(); 2715eaa3783bSRichard Henderson zero = tcg_const_reg(0); 2716b2167459SRichard Henderson 2717b2167459SRichard Henderson /* Form R1 << 1 | PSW[CB]{8}. */ 2718eaa3783bSRichard Henderson tcg_gen_add_reg(add1, in1, in1); 2719eaa3783bSRichard Henderson tcg_gen_add_reg(add1, add1, cpu_psw_cb_msb); 2720b2167459SRichard Henderson 2721b2167459SRichard Henderson /* Add or subtract R2, depending on PSW[V]. Proper computation of 2722b2167459SRichard Henderson carry{8} requires that we subtract via + ~R2 + 1, as described in 2723b2167459SRichard Henderson the manual. By extracting and masking V, we can produce the 2724b2167459SRichard Henderson proper inputs to the addition without movcond. */ 2725eaa3783bSRichard Henderson tcg_gen_sari_reg(addc, cpu_psw_v, TARGET_REGISTER_BITS - 1); 2726eaa3783bSRichard Henderson tcg_gen_xor_reg(add2, in2, addc); 2727eaa3783bSRichard Henderson tcg_gen_andi_reg(addc, addc, 1); 2728b2167459SRichard Henderson /* ??? This is only correct for 32-bit. */ 2729b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero); 2730b2167459SRichard Henderson tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero); 2731b2167459SRichard Henderson 2732b2167459SRichard Henderson tcg_temp_free(addc); 2733b2167459SRichard Henderson tcg_temp_free(zero); 2734b2167459SRichard Henderson 2735b2167459SRichard Henderson /* Write back the result register. */ 27360c982a28SRichard Henderson save_gpr(ctx, a->t, dest); 2737b2167459SRichard Henderson 2738b2167459SRichard Henderson /* Write back PSW[CB]. */ 2739eaa3783bSRichard Henderson tcg_gen_xor_reg(cpu_psw_cb, add1, add2); 2740eaa3783bSRichard Henderson tcg_gen_xor_reg(cpu_psw_cb, cpu_psw_cb, dest); 2741b2167459SRichard Henderson 2742b2167459SRichard Henderson /* Write back PSW[V] for the division step. */ 2743eaa3783bSRichard Henderson tcg_gen_neg_reg(cpu_psw_v, cpu_psw_cb_msb); 2744eaa3783bSRichard Henderson tcg_gen_xor_reg(cpu_psw_v, cpu_psw_v, in2); 2745b2167459SRichard Henderson 2746b2167459SRichard Henderson /* Install the new nullification. */ 27470c982a28SRichard Henderson if (a->cf) { 2748eaa3783bSRichard Henderson TCGv_reg sv = NULL; 27490c982a28SRichard Henderson if (a->cf >> 1 == 6) { 2750b2167459SRichard Henderson /* ??? The lshift is supposed to contribute to overflow. */ 2751b2167459SRichard Henderson sv = do_add_sv(ctx, dest, add1, add2); 2752b2167459SRichard Henderson } 27530c982a28SRichard Henderson ctx->null_cond = do_cond(a->cf, dest, cpu_psw_cb_msb, sv); 2754b2167459SRichard Henderson } 2755b2167459SRichard Henderson 2756b2167459SRichard Henderson tcg_temp_free(add1); 2757b2167459SRichard Henderson tcg_temp_free(add2); 2758b2167459SRichard Henderson tcg_temp_free(dest); 2759b2167459SRichard Henderson 276031234768SRichard Henderson return nullify_end(ctx); 2761b2167459SRichard Henderson } 2762b2167459SRichard Henderson 276331234768SRichard Henderson static bool trans_addi(DisasContext *ctx, uint32_t insn) 2764b2167459SRichard Henderson { 2765eaa3783bSRichard Henderson target_sreg im = low_sextract(insn, 0, 11); 2766b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 2767b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 2768b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2769b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 2770b2167459SRichard Henderson unsigned o1 = extract32(insn, 26, 1); 2771eaa3783bSRichard Henderson TCGv_reg tcg_im, tcg_r2; 2772b2167459SRichard Henderson 2773b2167459SRichard Henderson if (cf) { 2774b2167459SRichard Henderson nullify_over(ctx); 2775b2167459SRichard Henderson } 2776b2167459SRichard Henderson 2777b2167459SRichard Henderson tcg_im = load_const(ctx, im); 2778b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 277931234768SRichard Henderson do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf); 2780b2167459SRichard Henderson 278131234768SRichard Henderson return nullify_end(ctx); 2782b2167459SRichard Henderson } 2783b2167459SRichard Henderson 278431234768SRichard Henderson static bool trans_subi(DisasContext *ctx, uint32_t insn) 2785b2167459SRichard Henderson { 2786eaa3783bSRichard Henderson target_sreg im = low_sextract(insn, 0, 11); 2787b2167459SRichard Henderson unsigned e1 = extract32(insn, 11, 1); 2788b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 2789b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2790b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 2791eaa3783bSRichard Henderson TCGv_reg tcg_im, tcg_r2; 2792b2167459SRichard Henderson 2793b2167459SRichard Henderson if (cf) { 2794b2167459SRichard Henderson nullify_over(ctx); 2795b2167459SRichard Henderson } 2796b2167459SRichard Henderson 2797b2167459SRichard Henderson tcg_im = load_const(ctx, im); 2798b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 279931234768SRichard Henderson do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf); 2800b2167459SRichard Henderson 280131234768SRichard Henderson return nullify_end(ctx); 2802b2167459SRichard Henderson } 2803b2167459SRichard Henderson 280431234768SRichard Henderson static bool trans_cmpiclr(DisasContext *ctx, uint32_t insn) 2805b2167459SRichard Henderson { 2806eaa3783bSRichard Henderson target_sreg im = low_sextract(insn, 0, 11); 2807b2167459SRichard Henderson unsigned cf = extract32(insn, 12, 4); 2808b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2809b2167459SRichard Henderson unsigned r2 = extract32(insn, 21, 5); 2810eaa3783bSRichard Henderson TCGv_reg tcg_im, tcg_r2; 2811b2167459SRichard Henderson 2812b2167459SRichard Henderson if (cf) { 2813b2167459SRichard Henderson nullify_over(ctx); 2814b2167459SRichard Henderson } 2815b2167459SRichard Henderson 2816b2167459SRichard Henderson tcg_im = load_const(ctx, im); 2817b2167459SRichard Henderson tcg_r2 = load_gpr(ctx, r2); 281831234768SRichard Henderson do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf); 2819b2167459SRichard Henderson 282031234768SRichard Henderson return nullify_end(ctx); 2821b2167459SRichard Henderson } 2822b2167459SRichard Henderson 28231cd012a5SRichard Henderson static bool trans_ld(DisasContext *ctx, arg_ldst *a) 282496d6407fSRichard Henderson { 28251cd012a5SRichard Henderson return do_load(ctx, a->t, a->b, a->x, a->scale ? a->size : 0, 28261cd012a5SRichard Henderson a->disp, a->sp, a->m, a->size | MO_TE); 282796d6407fSRichard Henderson } 282896d6407fSRichard Henderson 28291cd012a5SRichard Henderson static bool trans_st(DisasContext *ctx, arg_ldst *a) 283096d6407fSRichard Henderson { 28311cd012a5SRichard Henderson assert(a->x == 0 && a->scale == 0); 28321cd012a5SRichard Henderson return do_store(ctx, a->t, a->b, a->disp, a->sp, a->m, a->size | MO_TE); 283396d6407fSRichard Henderson } 283496d6407fSRichard Henderson 28351cd012a5SRichard Henderson static bool trans_ldc(DisasContext *ctx, arg_ldst *a) 283696d6407fSRichard Henderson { 28371cd012a5SRichard Henderson TCGMemOp mop = MO_TEUL | MO_ALIGN_16 | a->size; 283886f8d05fSRichard Henderson TCGv_reg zero, dest, ofs; 283986f8d05fSRichard Henderson TCGv_tl addr; 284096d6407fSRichard Henderson 284196d6407fSRichard Henderson nullify_over(ctx); 284296d6407fSRichard Henderson 28431cd012a5SRichard Henderson if (a->m) { 284486f8d05fSRichard Henderson /* Base register modification. Make sure if RT == RB, 284586f8d05fSRichard Henderson we see the result of the load. */ 284696d6407fSRichard Henderson dest = get_temp(ctx); 284796d6407fSRichard Henderson } else { 28481cd012a5SRichard Henderson dest = dest_gpr(ctx, a->t); 284996d6407fSRichard Henderson } 285096d6407fSRichard Henderson 28511cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, a->x, a->scale ? a->size : 0, 28521cd012a5SRichard Henderson a->disp, a->sp, a->m, ctx->mmu_idx == MMU_PHYS_IDX); 2853eaa3783bSRichard Henderson zero = tcg_const_reg(0); 285486f8d05fSRichard Henderson tcg_gen_atomic_xchg_reg(dest, addr, zero, ctx->mmu_idx, mop); 28551cd012a5SRichard Henderson if (a->m) { 28561cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 285796d6407fSRichard Henderson } 28581cd012a5SRichard Henderson save_gpr(ctx, a->t, dest); 285996d6407fSRichard Henderson 286031234768SRichard Henderson return nullify_end(ctx); 286196d6407fSRichard Henderson } 286296d6407fSRichard Henderson 28631cd012a5SRichard Henderson static bool trans_stby(DisasContext *ctx, arg_stby *a) 286496d6407fSRichard Henderson { 286586f8d05fSRichard Henderson TCGv_reg ofs, val; 286686f8d05fSRichard Henderson TCGv_tl addr; 286796d6407fSRichard Henderson 286896d6407fSRichard Henderson nullify_over(ctx); 286996d6407fSRichard Henderson 28701cd012a5SRichard Henderson form_gva(ctx, &addr, &ofs, a->b, 0, 0, a->disp, a->sp, a->m, 287186f8d05fSRichard Henderson ctx->mmu_idx == MMU_PHYS_IDX); 28721cd012a5SRichard Henderson val = load_gpr(ctx, a->r); 28731cd012a5SRichard Henderson if (a->a) { 2874f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 2875f9f46db4SEmilio G. Cota gen_helper_stby_e_parallel(cpu_env, addr, val); 2876f9f46db4SEmilio G. Cota } else { 287796d6407fSRichard Henderson gen_helper_stby_e(cpu_env, addr, val); 2878f9f46db4SEmilio G. Cota } 2879f9f46db4SEmilio G. Cota } else { 2880f9f46db4SEmilio G. Cota if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 2881f9f46db4SEmilio G. Cota gen_helper_stby_b_parallel(cpu_env, addr, val); 288296d6407fSRichard Henderson } else { 288396d6407fSRichard Henderson gen_helper_stby_b(cpu_env, addr, val); 288496d6407fSRichard Henderson } 2885f9f46db4SEmilio G. Cota } 28861cd012a5SRichard Henderson if (a->m) { 288786f8d05fSRichard Henderson tcg_gen_andi_reg(ofs, ofs, ~3); 28881cd012a5SRichard Henderson save_gpr(ctx, a->b, ofs); 288996d6407fSRichard Henderson } 289096d6407fSRichard Henderson 289131234768SRichard Henderson return nullify_end(ctx); 289296d6407fSRichard Henderson } 289396d6407fSRichard Henderson 28941cd012a5SRichard Henderson static bool trans_lda(DisasContext *ctx, arg_ldst *a) 2895d0a851ccSRichard Henderson { 2896d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 2897d0a851ccSRichard Henderson 2898d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2899d0a851ccSRichard Henderson ctx->mmu_idx = MMU_PHYS_IDX; 29001cd012a5SRichard Henderson trans_ld(ctx, a); 2901d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 290231234768SRichard Henderson return true; 2903d0a851ccSRichard Henderson } 2904d0a851ccSRichard Henderson 29051cd012a5SRichard Henderson static bool trans_sta(DisasContext *ctx, arg_ldst *a) 2906d0a851ccSRichard Henderson { 2907d0a851ccSRichard Henderson int hold_mmu_idx = ctx->mmu_idx; 2908d0a851ccSRichard Henderson 2909d0a851ccSRichard Henderson CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR); 2910d0a851ccSRichard Henderson ctx->mmu_idx = MMU_PHYS_IDX; 29111cd012a5SRichard Henderson trans_st(ctx, a); 2912d0a851ccSRichard Henderson ctx->mmu_idx = hold_mmu_idx; 291331234768SRichard Henderson return true; 2914d0a851ccSRichard Henderson } 291595412a61SRichard Henderson 291631234768SRichard Henderson static bool trans_ldil(DisasContext *ctx, uint32_t insn) 2917b2167459SRichard Henderson { 2918b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 2919eaa3783bSRichard Henderson target_sreg i = assemble_21(insn); 2920eaa3783bSRichard Henderson TCGv_reg tcg_rt = dest_gpr(ctx, rt); 2921b2167459SRichard Henderson 2922eaa3783bSRichard Henderson tcg_gen_movi_reg(tcg_rt, i); 2923b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 2924b2167459SRichard Henderson cond_free(&ctx->null_cond); 292531234768SRichard Henderson return true; 2926b2167459SRichard Henderson } 2927b2167459SRichard Henderson 292831234768SRichard Henderson static bool trans_addil(DisasContext *ctx, uint32_t insn) 2929b2167459SRichard Henderson { 2930b2167459SRichard Henderson unsigned rt = extract32(insn, 21, 5); 2931eaa3783bSRichard Henderson target_sreg i = assemble_21(insn); 2932eaa3783bSRichard Henderson TCGv_reg tcg_rt = load_gpr(ctx, rt); 2933eaa3783bSRichard Henderson TCGv_reg tcg_r1 = dest_gpr(ctx, 1); 2934b2167459SRichard Henderson 2935eaa3783bSRichard Henderson tcg_gen_addi_reg(tcg_r1, tcg_rt, i); 2936b2167459SRichard Henderson save_gpr(ctx, 1, tcg_r1); 2937b2167459SRichard Henderson cond_free(&ctx->null_cond); 293831234768SRichard Henderson return true; 2939b2167459SRichard Henderson } 2940b2167459SRichard Henderson 294131234768SRichard Henderson static bool trans_ldo(DisasContext *ctx, uint32_t insn) 2942b2167459SRichard Henderson { 2943b2167459SRichard Henderson unsigned rb = extract32(insn, 21, 5); 2944b2167459SRichard Henderson unsigned rt = extract32(insn, 16, 5); 2945eaa3783bSRichard Henderson target_sreg i = assemble_16(insn); 2946eaa3783bSRichard Henderson TCGv_reg tcg_rt = dest_gpr(ctx, rt); 2947b2167459SRichard Henderson 2948b2167459SRichard Henderson /* Special case rb == 0, for the LDI pseudo-op. 2949b2167459SRichard Henderson The COPY pseudo-op is handled for free within tcg_gen_addi_tl. */ 2950b2167459SRichard Henderson if (rb == 0) { 2951eaa3783bSRichard Henderson tcg_gen_movi_reg(tcg_rt, i); 2952b2167459SRichard Henderson } else { 2953eaa3783bSRichard Henderson tcg_gen_addi_reg(tcg_rt, cpu_gr[rb], i); 2954b2167459SRichard Henderson } 2955b2167459SRichard Henderson save_gpr(ctx, rt, tcg_rt); 2956b2167459SRichard Henderson cond_free(&ctx->null_cond); 295731234768SRichard Henderson return true; 2958b2167459SRichard Henderson } 2959b2167459SRichard Henderson 296031234768SRichard Henderson static bool trans_load(DisasContext *ctx, uint32_t insn, 296196d6407fSRichard Henderson bool is_mod, TCGMemOp mop) 296296d6407fSRichard Henderson { 296396d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 296496d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 296586f8d05fSRichard Henderson unsigned sp = extract32(insn, 14, 2); 2966eaa3783bSRichard Henderson target_sreg i = assemble_16(insn); 296796d6407fSRichard Henderson 296831234768SRichard Henderson do_load(ctx, rt, rb, 0, 0, i, sp, is_mod ? (i < 0 ? -1 : 1) : 0, mop); 296931234768SRichard Henderson return true; 297096d6407fSRichard Henderson } 297196d6407fSRichard Henderson 297231234768SRichard Henderson static bool trans_load_w(DisasContext *ctx, uint32_t insn) 297396d6407fSRichard Henderson { 297496d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 297596d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 297686f8d05fSRichard Henderson unsigned sp = extract32(insn, 14, 2); 2977eaa3783bSRichard Henderson target_sreg i = assemble_16a(insn); 297896d6407fSRichard Henderson unsigned ext2 = extract32(insn, 1, 2); 297996d6407fSRichard Henderson 298096d6407fSRichard Henderson switch (ext2) { 298196d6407fSRichard Henderson case 0: 298296d6407fSRichard Henderson case 1: 298396d6407fSRichard Henderson /* FLDW without modification. */ 298431234768SRichard Henderson do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, sp, 0); 298531234768SRichard Henderson break; 298696d6407fSRichard Henderson case 2: 298796d6407fSRichard Henderson /* LDW with modification. Note that the sign of I selects 298896d6407fSRichard Henderson post-dec vs pre-inc. */ 298931234768SRichard Henderson do_load(ctx, rt, rb, 0, 0, i, sp, (i < 0 ? 1 : -1), MO_TEUL); 299031234768SRichard Henderson break; 299196d6407fSRichard Henderson default: 299296d6407fSRichard Henderson return gen_illegal(ctx); 299396d6407fSRichard Henderson } 299431234768SRichard Henderson return true; 299596d6407fSRichard Henderson } 299696d6407fSRichard Henderson 299731234768SRichard Henderson static bool trans_fload_mod(DisasContext *ctx, uint32_t insn) 299896d6407fSRichard Henderson { 2999eaa3783bSRichard Henderson target_sreg i = assemble_16a(insn); 300096d6407fSRichard Henderson unsigned t1 = extract32(insn, 1, 1); 300196d6407fSRichard Henderson unsigned a = extract32(insn, 2, 1); 300286f8d05fSRichard Henderson unsigned sp = extract32(insn, 14, 2); 300396d6407fSRichard Henderson unsigned t0 = extract32(insn, 16, 5); 300496d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 300596d6407fSRichard Henderson 300696d6407fSRichard Henderson /* FLDW with modification. */ 300731234768SRichard Henderson do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, sp, (a ? -1 : 1)); 300831234768SRichard Henderson return true; 300996d6407fSRichard Henderson } 301096d6407fSRichard Henderson 301131234768SRichard Henderson static bool trans_store(DisasContext *ctx, uint32_t insn, 301296d6407fSRichard Henderson bool is_mod, TCGMemOp mop) 301396d6407fSRichard Henderson { 301496d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 301596d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 301686f8d05fSRichard Henderson unsigned sp = extract32(insn, 14, 2); 3017eaa3783bSRichard Henderson target_sreg i = assemble_16(insn); 301896d6407fSRichard Henderson 301931234768SRichard Henderson do_store(ctx, rt, rb, i, sp, is_mod ? (i < 0 ? -1 : 1) : 0, mop); 302031234768SRichard Henderson return true; 302196d6407fSRichard Henderson } 302296d6407fSRichard Henderson 302331234768SRichard Henderson static bool trans_store_w(DisasContext *ctx, uint32_t insn) 302496d6407fSRichard Henderson { 302596d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 302696d6407fSRichard Henderson unsigned rt = extract32(insn, 16, 5); 302786f8d05fSRichard Henderson unsigned sp = extract32(insn, 14, 2); 3028eaa3783bSRichard Henderson target_sreg i = assemble_16a(insn); 302996d6407fSRichard Henderson unsigned ext2 = extract32(insn, 1, 2); 303096d6407fSRichard Henderson 303196d6407fSRichard Henderson switch (ext2) { 303296d6407fSRichard Henderson case 0: 303396d6407fSRichard Henderson case 1: 303496d6407fSRichard Henderson /* FSTW without modification. */ 303531234768SRichard Henderson do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, sp, 0); 303631234768SRichard Henderson break; 303796d6407fSRichard Henderson case 2: 30383f7367e2SHelge Deller /* STW with modification. */ 303931234768SRichard Henderson do_store(ctx, rt, rb, i, sp, (i < 0 ? 1 : -1), MO_TEUL); 304031234768SRichard Henderson break; 304196d6407fSRichard Henderson default: 304296d6407fSRichard Henderson return gen_illegal(ctx); 304396d6407fSRichard Henderson } 304431234768SRichard Henderson return true; 304596d6407fSRichard Henderson } 304696d6407fSRichard Henderson 304731234768SRichard Henderson static bool trans_fstore_mod(DisasContext *ctx, uint32_t insn) 304896d6407fSRichard Henderson { 3049eaa3783bSRichard Henderson target_sreg i = assemble_16a(insn); 305096d6407fSRichard Henderson unsigned t1 = extract32(insn, 1, 1); 305196d6407fSRichard Henderson unsigned a = extract32(insn, 2, 1); 305286f8d05fSRichard Henderson unsigned sp = extract32(insn, 14, 2); 305396d6407fSRichard Henderson unsigned t0 = extract32(insn, 16, 5); 305496d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 305596d6407fSRichard Henderson 305696d6407fSRichard Henderson /* FSTW with modification. */ 305731234768SRichard Henderson do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, sp, (a ? -1 : 1)); 305831234768SRichard Henderson return true; 305996d6407fSRichard Henderson } 306096d6407fSRichard Henderson 306131234768SRichard Henderson static bool trans_copr_w(DisasContext *ctx, uint32_t insn) 306296d6407fSRichard Henderson { 306396d6407fSRichard Henderson unsigned t0 = extract32(insn, 0, 5); 306496d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 306596d6407fSRichard Henderson unsigned t1 = extract32(insn, 6, 1); 306696d6407fSRichard Henderson unsigned ext3 = extract32(insn, 7, 3); 306796d6407fSRichard Henderson /* unsigned cc = extract32(insn, 10, 2); */ 306896d6407fSRichard Henderson unsigned i = extract32(insn, 12, 1); 306996d6407fSRichard Henderson unsigned ua = extract32(insn, 13, 1); 307086f8d05fSRichard Henderson unsigned sp = extract32(insn, 14, 2); 307196d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 307296d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 307396d6407fSRichard Henderson unsigned rt = t1 * 32 + t0; 307496d6407fSRichard Henderson int modify = (m ? (ua ? -1 : 1) : 0); 307596d6407fSRichard Henderson int disp, scale; 307696d6407fSRichard Henderson 307796d6407fSRichard Henderson if (i == 0) { 307896d6407fSRichard Henderson scale = (ua ? 2 : 0); 307996d6407fSRichard Henderson disp = 0; 308096d6407fSRichard Henderson modify = m; 308196d6407fSRichard Henderson } else { 308296d6407fSRichard Henderson disp = low_sextract(rx, 0, 5); 308396d6407fSRichard Henderson scale = 0; 308496d6407fSRichard Henderson rx = 0; 308596d6407fSRichard Henderson modify = (m ? (ua ? -1 : 1) : 0); 308696d6407fSRichard Henderson } 308796d6407fSRichard Henderson 308896d6407fSRichard Henderson switch (ext3) { 308996d6407fSRichard Henderson case 0: /* FLDW */ 309031234768SRichard Henderson do_floadw(ctx, rt, rb, rx, scale, disp, sp, modify); 309131234768SRichard Henderson break; 309296d6407fSRichard Henderson case 4: /* FSTW */ 309331234768SRichard Henderson do_fstorew(ctx, rt, rb, rx, scale, disp, sp, modify); 309431234768SRichard Henderson break; 309531234768SRichard Henderson default: 309696d6407fSRichard Henderson return gen_illegal(ctx); 309796d6407fSRichard Henderson } 309831234768SRichard Henderson return true; 309931234768SRichard Henderson } 310096d6407fSRichard Henderson 310131234768SRichard Henderson static bool trans_copr_dw(DisasContext *ctx, uint32_t insn) 310296d6407fSRichard Henderson { 310396d6407fSRichard Henderson unsigned rt = extract32(insn, 0, 5); 310496d6407fSRichard Henderson unsigned m = extract32(insn, 5, 1); 310596d6407fSRichard Henderson unsigned ext4 = extract32(insn, 6, 4); 310696d6407fSRichard Henderson /* unsigned cc = extract32(insn, 10, 2); */ 310796d6407fSRichard Henderson unsigned i = extract32(insn, 12, 1); 310896d6407fSRichard Henderson unsigned ua = extract32(insn, 13, 1); 310986f8d05fSRichard Henderson unsigned sp = extract32(insn, 14, 2); 311096d6407fSRichard Henderson unsigned rx = extract32(insn, 16, 5); 311196d6407fSRichard Henderson unsigned rb = extract32(insn, 21, 5); 311296d6407fSRichard Henderson int modify = (m ? (ua ? -1 : 1) : 0); 311396d6407fSRichard Henderson int disp, scale; 311496d6407fSRichard Henderson 311596d6407fSRichard Henderson if (i == 0) { 311696d6407fSRichard Henderson scale = (ua ? 3 : 0); 311796d6407fSRichard Henderson disp = 0; 311896d6407fSRichard Henderson modify = m; 311996d6407fSRichard Henderson } else { 312096d6407fSRichard Henderson disp = low_sextract(rx, 0, 5); 312196d6407fSRichard Henderson scale = 0; 312296d6407fSRichard Henderson rx = 0; 312396d6407fSRichard Henderson modify = (m ? (ua ? -1 : 1) : 0); 312496d6407fSRichard Henderson } 312596d6407fSRichard Henderson 312696d6407fSRichard Henderson switch (ext4) { 312796d6407fSRichard Henderson case 0: /* FLDD */ 312831234768SRichard Henderson do_floadd(ctx, rt, rb, rx, scale, disp, sp, modify); 312931234768SRichard Henderson break; 313096d6407fSRichard Henderson case 8: /* FSTD */ 313131234768SRichard Henderson do_fstored(ctx, rt, rb, rx, scale, disp, sp, modify); 313231234768SRichard Henderson break; 313396d6407fSRichard Henderson default: 313496d6407fSRichard Henderson return gen_illegal(ctx); 313596d6407fSRichard Henderson } 313631234768SRichard Henderson return true; 313796d6407fSRichard Henderson } 313896d6407fSRichard Henderson 313901afb7beSRichard Henderson static bool do_cmpb(DisasContext *ctx, unsigned r, TCGv_reg in1, 314001afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 314198cd9ca7SRichard Henderson { 314201afb7beSRichard Henderson TCGv_reg dest, in2, sv; 314398cd9ca7SRichard Henderson DisasCond cond; 314498cd9ca7SRichard Henderson 314598cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 314698cd9ca7SRichard Henderson dest = get_temp(ctx); 314798cd9ca7SRichard Henderson 3148eaa3783bSRichard Henderson tcg_gen_sub_reg(dest, in1, in2); 314998cd9ca7SRichard Henderson 3150f764718dSRichard Henderson sv = NULL; 315198cd9ca7SRichard Henderson if (c == 6) { 315298cd9ca7SRichard Henderson sv = do_sub_sv(ctx, dest, in1, in2); 315398cd9ca7SRichard Henderson } 315498cd9ca7SRichard Henderson 315501afb7beSRichard Henderson cond = do_sub_cond(c * 2 + f, dest, in1, in2, sv); 315601afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 315798cd9ca7SRichard Henderson } 315898cd9ca7SRichard Henderson 315901afb7beSRichard Henderson static bool trans_cmpb(DisasContext *ctx, arg_cmpb *a) 316098cd9ca7SRichard Henderson { 316101afb7beSRichard Henderson nullify_over(ctx); 316201afb7beSRichard Henderson return do_cmpb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 316301afb7beSRichard Henderson } 316401afb7beSRichard Henderson 316501afb7beSRichard Henderson static bool trans_cmpbi(DisasContext *ctx, arg_cmpbi *a) 316601afb7beSRichard Henderson { 316701afb7beSRichard Henderson nullify_over(ctx); 316801afb7beSRichard Henderson return do_cmpb(ctx, a->r, load_const(ctx, a->i), a->c, a->f, a->n, a->disp); 316901afb7beSRichard Henderson } 317001afb7beSRichard Henderson 317101afb7beSRichard Henderson static bool do_addb(DisasContext *ctx, unsigned r, TCGv_reg in1, 317201afb7beSRichard Henderson unsigned c, unsigned f, unsigned n, int disp) 317301afb7beSRichard Henderson { 317401afb7beSRichard Henderson TCGv_reg dest, in2, sv, cb_msb; 317598cd9ca7SRichard Henderson DisasCond cond; 317698cd9ca7SRichard Henderson 317798cd9ca7SRichard Henderson in2 = load_gpr(ctx, r); 317898cd9ca7SRichard Henderson dest = dest_gpr(ctx, r); 3179f764718dSRichard Henderson sv = NULL; 3180f764718dSRichard Henderson cb_msb = NULL; 318198cd9ca7SRichard Henderson 318298cd9ca7SRichard Henderson switch (c) { 318398cd9ca7SRichard Henderson default: 3184eaa3783bSRichard Henderson tcg_gen_add_reg(dest, in1, in2); 318598cd9ca7SRichard Henderson break; 318698cd9ca7SRichard Henderson case 4: case 5: 318798cd9ca7SRichard Henderson cb_msb = get_temp(ctx); 3188eaa3783bSRichard Henderson tcg_gen_movi_reg(cb_msb, 0); 3189eaa3783bSRichard Henderson tcg_gen_add2_reg(dest, cb_msb, in1, cb_msb, in2, cb_msb); 319098cd9ca7SRichard Henderson break; 319198cd9ca7SRichard Henderson case 6: 3192eaa3783bSRichard Henderson tcg_gen_add_reg(dest, in1, in2); 319398cd9ca7SRichard Henderson sv = do_add_sv(ctx, dest, in1, in2); 319498cd9ca7SRichard Henderson break; 319598cd9ca7SRichard Henderson } 319698cd9ca7SRichard Henderson 319701afb7beSRichard Henderson cond = do_cond(c * 2 + f, dest, cb_msb, sv); 319801afb7beSRichard Henderson return do_cbranch(ctx, disp, n, &cond); 319998cd9ca7SRichard Henderson } 320098cd9ca7SRichard Henderson 320101afb7beSRichard Henderson static bool trans_addb(DisasContext *ctx, arg_addb *a) 320298cd9ca7SRichard Henderson { 320301afb7beSRichard Henderson nullify_over(ctx); 320401afb7beSRichard Henderson return do_addb(ctx, a->r2, load_gpr(ctx, a->r1), a->c, a->f, a->n, a->disp); 320501afb7beSRichard Henderson } 320601afb7beSRichard Henderson 320701afb7beSRichard Henderson static bool trans_addbi(DisasContext *ctx, arg_addbi *a) 320801afb7beSRichard Henderson { 320901afb7beSRichard Henderson nullify_over(ctx); 321001afb7beSRichard Henderson return do_addb(ctx, a->r, load_const(ctx, a->i), a->c, a->f, a->n, a->disp); 321101afb7beSRichard Henderson } 321201afb7beSRichard Henderson 321301afb7beSRichard Henderson static bool trans_bb_sar(DisasContext *ctx, arg_bb_sar *a) 321401afb7beSRichard Henderson { 3215eaa3783bSRichard Henderson TCGv_reg tmp, tcg_r; 321698cd9ca7SRichard Henderson DisasCond cond; 321798cd9ca7SRichard Henderson 321898cd9ca7SRichard Henderson nullify_over(ctx); 321998cd9ca7SRichard Henderson 322098cd9ca7SRichard Henderson tmp = tcg_temp_new(); 322101afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 3222eaa3783bSRichard Henderson tcg_gen_shl_reg(tmp, tcg_r, cpu_sar); 322398cd9ca7SRichard Henderson 322401afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 322598cd9ca7SRichard Henderson tcg_temp_free(tmp); 322601afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 322798cd9ca7SRichard Henderson } 322898cd9ca7SRichard Henderson 322901afb7beSRichard Henderson static bool trans_bb_imm(DisasContext *ctx, arg_bb_imm *a) 323098cd9ca7SRichard Henderson { 323101afb7beSRichard Henderson TCGv_reg tmp, tcg_r; 323201afb7beSRichard Henderson DisasCond cond; 323301afb7beSRichard Henderson 323401afb7beSRichard Henderson nullify_over(ctx); 323501afb7beSRichard Henderson 323601afb7beSRichard Henderson tmp = tcg_temp_new(); 323701afb7beSRichard Henderson tcg_r = load_gpr(ctx, a->r); 323801afb7beSRichard Henderson tcg_gen_shli_reg(tmp, tcg_r, a->p); 323901afb7beSRichard Henderson 324001afb7beSRichard Henderson cond = cond_make_0(a->c ? TCG_COND_GE : TCG_COND_LT, tmp); 324101afb7beSRichard Henderson tcg_temp_free(tmp); 324201afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 324301afb7beSRichard Henderson } 324401afb7beSRichard Henderson 324501afb7beSRichard Henderson static bool trans_movb(DisasContext *ctx, arg_movb *a) 324601afb7beSRichard Henderson { 3247eaa3783bSRichard Henderson TCGv_reg dest; 324898cd9ca7SRichard Henderson DisasCond cond; 324998cd9ca7SRichard Henderson 325098cd9ca7SRichard Henderson nullify_over(ctx); 325198cd9ca7SRichard Henderson 325201afb7beSRichard Henderson dest = dest_gpr(ctx, a->r2); 325301afb7beSRichard Henderson if (a->r1 == 0) { 3254eaa3783bSRichard Henderson tcg_gen_movi_reg(dest, 0); 325598cd9ca7SRichard Henderson } else { 325601afb7beSRichard Henderson tcg_gen_mov_reg(dest, cpu_gr[a->r1]); 325798cd9ca7SRichard Henderson } 325898cd9ca7SRichard Henderson 325901afb7beSRichard Henderson cond = do_sed_cond(a->c, dest); 326001afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 326101afb7beSRichard Henderson } 326201afb7beSRichard Henderson 326301afb7beSRichard Henderson static bool trans_movbi(DisasContext *ctx, arg_movbi *a) 326401afb7beSRichard Henderson { 326501afb7beSRichard Henderson TCGv_reg dest; 326601afb7beSRichard Henderson DisasCond cond; 326701afb7beSRichard Henderson 326801afb7beSRichard Henderson nullify_over(ctx); 326901afb7beSRichard Henderson 327001afb7beSRichard Henderson dest = dest_gpr(ctx, a->r); 327101afb7beSRichard Henderson tcg_gen_movi_reg(dest, a->i); 327201afb7beSRichard Henderson 327301afb7beSRichard Henderson cond = do_sed_cond(a->c, dest); 327401afb7beSRichard Henderson return do_cbranch(ctx, a->disp, a->n, &cond); 327598cd9ca7SRichard Henderson } 327698cd9ca7SRichard Henderson 327730878590SRichard Henderson static bool trans_shrpw_sar(DisasContext *ctx, arg_shrpw_sar *a) 32780b1347d2SRichard Henderson { 3279eaa3783bSRichard Henderson TCGv_reg dest; 32800b1347d2SRichard Henderson 328130878590SRichard Henderson if (a->c) { 32820b1347d2SRichard Henderson nullify_over(ctx); 32830b1347d2SRichard Henderson } 32840b1347d2SRichard Henderson 328530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 328630878590SRichard Henderson if (a->r1 == 0) { 328730878590SRichard Henderson tcg_gen_ext32u_reg(dest, load_gpr(ctx, a->r2)); 3288eaa3783bSRichard Henderson tcg_gen_shr_reg(dest, dest, cpu_sar); 328930878590SRichard Henderson } else if (a->r1 == a->r2) { 32900b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 329130878590SRichard Henderson tcg_gen_trunc_reg_i32(t32, load_gpr(ctx, a->r2)); 32920b1347d2SRichard Henderson tcg_gen_rotr_i32(t32, t32, cpu_sar); 3293eaa3783bSRichard Henderson tcg_gen_extu_i32_reg(dest, t32); 32940b1347d2SRichard Henderson tcg_temp_free_i32(t32); 32950b1347d2SRichard Henderson } else { 32960b1347d2SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 32970b1347d2SRichard Henderson TCGv_i64 s = tcg_temp_new_i64(); 32980b1347d2SRichard Henderson 329930878590SRichard Henderson tcg_gen_concat_reg_i64(t, load_gpr(ctx, a->r2), load_gpr(ctx, a->r1)); 3300eaa3783bSRichard Henderson tcg_gen_extu_reg_i64(s, cpu_sar); 33010b1347d2SRichard Henderson tcg_gen_shr_i64(t, t, s); 3302eaa3783bSRichard Henderson tcg_gen_trunc_i64_reg(dest, t); 33030b1347d2SRichard Henderson 33040b1347d2SRichard Henderson tcg_temp_free_i64(t); 33050b1347d2SRichard Henderson tcg_temp_free_i64(s); 33060b1347d2SRichard Henderson } 330730878590SRichard Henderson save_gpr(ctx, a->t, dest); 33080b1347d2SRichard Henderson 33090b1347d2SRichard Henderson /* Install the new nullification. */ 33100b1347d2SRichard Henderson cond_free(&ctx->null_cond); 331130878590SRichard Henderson if (a->c) { 331230878590SRichard Henderson ctx->null_cond = do_sed_cond(a->c, dest); 33130b1347d2SRichard Henderson } 331431234768SRichard Henderson return nullify_end(ctx); 33150b1347d2SRichard Henderson } 33160b1347d2SRichard Henderson 331730878590SRichard Henderson static bool trans_shrpw_imm(DisasContext *ctx, arg_shrpw_imm *a) 33180b1347d2SRichard Henderson { 331930878590SRichard Henderson unsigned sa = 31 - a->cpos; 3320eaa3783bSRichard Henderson TCGv_reg dest, t2; 33210b1347d2SRichard Henderson 332230878590SRichard Henderson if (a->c) { 33230b1347d2SRichard Henderson nullify_over(ctx); 33240b1347d2SRichard Henderson } 33250b1347d2SRichard Henderson 332630878590SRichard Henderson dest = dest_gpr(ctx, a->t); 332730878590SRichard Henderson t2 = load_gpr(ctx, a->r2); 332830878590SRichard Henderson if (a->r1 == a->r2) { 33290b1347d2SRichard Henderson TCGv_i32 t32 = tcg_temp_new_i32(); 3330eaa3783bSRichard Henderson tcg_gen_trunc_reg_i32(t32, t2); 33310b1347d2SRichard Henderson tcg_gen_rotri_i32(t32, t32, sa); 3332eaa3783bSRichard Henderson tcg_gen_extu_i32_reg(dest, t32); 33330b1347d2SRichard Henderson tcg_temp_free_i32(t32); 333430878590SRichard Henderson } else if (a->r1 == 0) { 3335eaa3783bSRichard Henderson tcg_gen_extract_reg(dest, t2, sa, 32 - sa); 33360b1347d2SRichard Henderson } else { 3337eaa3783bSRichard Henderson TCGv_reg t0 = tcg_temp_new(); 3338eaa3783bSRichard Henderson tcg_gen_extract_reg(t0, t2, sa, 32 - sa); 333930878590SRichard Henderson tcg_gen_deposit_reg(dest, t0, cpu_gr[a->r1], 32 - sa, sa); 33400b1347d2SRichard Henderson tcg_temp_free(t0); 33410b1347d2SRichard Henderson } 334230878590SRichard Henderson save_gpr(ctx, a->t, dest); 33430b1347d2SRichard Henderson 33440b1347d2SRichard Henderson /* Install the new nullification. */ 33450b1347d2SRichard Henderson cond_free(&ctx->null_cond); 334630878590SRichard Henderson if (a->c) { 334730878590SRichard Henderson ctx->null_cond = do_sed_cond(a->c, dest); 33480b1347d2SRichard Henderson } 334931234768SRichard Henderson return nullify_end(ctx); 33500b1347d2SRichard Henderson } 33510b1347d2SRichard Henderson 335230878590SRichard Henderson static bool trans_extrw_sar(DisasContext *ctx, arg_extrw_sar *a) 33530b1347d2SRichard Henderson { 335430878590SRichard Henderson unsigned len = 32 - a->clen; 3355eaa3783bSRichard Henderson TCGv_reg dest, src, tmp; 33560b1347d2SRichard Henderson 335730878590SRichard Henderson if (a->c) { 33580b1347d2SRichard Henderson nullify_over(ctx); 33590b1347d2SRichard Henderson } 33600b1347d2SRichard Henderson 336130878590SRichard Henderson dest = dest_gpr(ctx, a->t); 336230878590SRichard Henderson src = load_gpr(ctx, a->r); 33630b1347d2SRichard Henderson tmp = tcg_temp_new(); 33640b1347d2SRichard Henderson 33650b1347d2SRichard Henderson /* Recall that SAR is using big-endian bit numbering. */ 3366eaa3783bSRichard Henderson tcg_gen_xori_reg(tmp, cpu_sar, TARGET_REGISTER_BITS - 1); 336730878590SRichard Henderson if (a->se) { 3368eaa3783bSRichard Henderson tcg_gen_sar_reg(dest, src, tmp); 3369eaa3783bSRichard Henderson tcg_gen_sextract_reg(dest, dest, 0, len); 33700b1347d2SRichard Henderson } else { 3371eaa3783bSRichard Henderson tcg_gen_shr_reg(dest, src, tmp); 3372eaa3783bSRichard Henderson tcg_gen_extract_reg(dest, dest, 0, len); 33730b1347d2SRichard Henderson } 33740b1347d2SRichard Henderson tcg_temp_free(tmp); 337530878590SRichard Henderson save_gpr(ctx, a->t, dest); 33760b1347d2SRichard Henderson 33770b1347d2SRichard Henderson /* Install the new nullification. */ 33780b1347d2SRichard Henderson cond_free(&ctx->null_cond); 337930878590SRichard Henderson if (a->c) { 338030878590SRichard Henderson ctx->null_cond = do_sed_cond(a->c, dest); 33810b1347d2SRichard Henderson } 338231234768SRichard Henderson return nullify_end(ctx); 33830b1347d2SRichard Henderson } 33840b1347d2SRichard Henderson 338530878590SRichard Henderson static bool trans_extrw_imm(DisasContext *ctx, arg_extrw_imm *a) 33860b1347d2SRichard Henderson { 338730878590SRichard Henderson unsigned len = 32 - a->clen; 338830878590SRichard Henderson unsigned cpos = 31 - a->pos; 3389eaa3783bSRichard Henderson TCGv_reg dest, src; 33900b1347d2SRichard Henderson 339130878590SRichard Henderson if (a->c) { 33920b1347d2SRichard Henderson nullify_over(ctx); 33930b1347d2SRichard Henderson } 33940b1347d2SRichard Henderson 339530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 339630878590SRichard Henderson src = load_gpr(ctx, a->r); 339730878590SRichard Henderson if (a->se) { 3398eaa3783bSRichard Henderson tcg_gen_sextract_reg(dest, src, cpos, len); 33990b1347d2SRichard Henderson } else { 3400eaa3783bSRichard Henderson tcg_gen_extract_reg(dest, src, cpos, len); 34010b1347d2SRichard Henderson } 340230878590SRichard Henderson save_gpr(ctx, a->t, dest); 34030b1347d2SRichard Henderson 34040b1347d2SRichard Henderson /* Install the new nullification. */ 34050b1347d2SRichard Henderson cond_free(&ctx->null_cond); 340630878590SRichard Henderson if (a->c) { 340730878590SRichard Henderson ctx->null_cond = do_sed_cond(a->c, dest); 34080b1347d2SRichard Henderson } 340931234768SRichard Henderson return nullify_end(ctx); 34100b1347d2SRichard Henderson } 34110b1347d2SRichard Henderson 341230878590SRichard Henderson static bool trans_depwi_imm(DisasContext *ctx, arg_depwi_imm *a) 34130b1347d2SRichard Henderson { 341430878590SRichard Henderson unsigned len = 32 - a->clen; 3415eaa3783bSRichard Henderson target_sreg mask0, mask1; 3416eaa3783bSRichard Henderson TCGv_reg dest; 34170b1347d2SRichard Henderson 341830878590SRichard Henderson if (a->c) { 34190b1347d2SRichard Henderson nullify_over(ctx); 34200b1347d2SRichard Henderson } 342130878590SRichard Henderson if (a->cpos + len > 32) { 342230878590SRichard Henderson len = 32 - a->cpos; 34230b1347d2SRichard Henderson } 34240b1347d2SRichard Henderson 342530878590SRichard Henderson dest = dest_gpr(ctx, a->t); 342630878590SRichard Henderson mask0 = deposit64(0, a->cpos, len, a->i); 342730878590SRichard Henderson mask1 = deposit64(-1, a->cpos, len, a->i); 34280b1347d2SRichard Henderson 342930878590SRichard Henderson if (a->nz) { 343030878590SRichard Henderson TCGv_reg src = load_gpr(ctx, a->t); 34310b1347d2SRichard Henderson if (mask1 != -1) { 3432eaa3783bSRichard Henderson tcg_gen_andi_reg(dest, src, mask1); 34330b1347d2SRichard Henderson src = dest; 34340b1347d2SRichard Henderson } 3435eaa3783bSRichard Henderson tcg_gen_ori_reg(dest, src, mask0); 34360b1347d2SRichard Henderson } else { 3437eaa3783bSRichard Henderson tcg_gen_movi_reg(dest, mask0); 34380b1347d2SRichard Henderson } 343930878590SRichard Henderson save_gpr(ctx, a->t, dest); 34400b1347d2SRichard Henderson 34410b1347d2SRichard Henderson /* Install the new nullification. */ 34420b1347d2SRichard Henderson cond_free(&ctx->null_cond); 344330878590SRichard Henderson if (a->c) { 344430878590SRichard Henderson ctx->null_cond = do_sed_cond(a->c, dest); 34450b1347d2SRichard Henderson } 344631234768SRichard Henderson return nullify_end(ctx); 34470b1347d2SRichard Henderson } 34480b1347d2SRichard Henderson 344930878590SRichard Henderson static bool trans_depw_imm(DisasContext *ctx, arg_depw_imm *a) 34500b1347d2SRichard Henderson { 345130878590SRichard Henderson unsigned rs = a->nz ? a->t : 0; 345230878590SRichard Henderson unsigned len = 32 - a->clen; 3453eaa3783bSRichard Henderson TCGv_reg dest, val; 34540b1347d2SRichard Henderson 345530878590SRichard Henderson if (a->c) { 34560b1347d2SRichard Henderson nullify_over(ctx); 34570b1347d2SRichard Henderson } 345830878590SRichard Henderson if (a->cpos + len > 32) { 345930878590SRichard Henderson len = 32 - a->cpos; 34600b1347d2SRichard Henderson } 34610b1347d2SRichard Henderson 346230878590SRichard Henderson dest = dest_gpr(ctx, a->t); 346330878590SRichard Henderson val = load_gpr(ctx, a->r); 34640b1347d2SRichard Henderson if (rs == 0) { 346530878590SRichard Henderson tcg_gen_deposit_z_reg(dest, val, a->cpos, len); 34660b1347d2SRichard Henderson } else { 346730878590SRichard Henderson tcg_gen_deposit_reg(dest, cpu_gr[rs], val, a->cpos, len); 34680b1347d2SRichard Henderson } 346930878590SRichard Henderson save_gpr(ctx, a->t, dest); 34700b1347d2SRichard Henderson 34710b1347d2SRichard Henderson /* Install the new nullification. */ 34720b1347d2SRichard Henderson cond_free(&ctx->null_cond); 347330878590SRichard Henderson if (a->c) { 347430878590SRichard Henderson ctx->null_cond = do_sed_cond(a->c, dest); 34750b1347d2SRichard Henderson } 347631234768SRichard Henderson return nullify_end(ctx); 34770b1347d2SRichard Henderson } 34780b1347d2SRichard Henderson 347930878590SRichard Henderson static bool do_depw_sar(DisasContext *ctx, unsigned rt, unsigned c, 348030878590SRichard Henderson unsigned nz, unsigned clen, TCGv_reg val) 34810b1347d2SRichard Henderson { 34820b1347d2SRichard Henderson unsigned rs = nz ? rt : 0; 34830b1347d2SRichard Henderson unsigned len = 32 - clen; 348430878590SRichard Henderson TCGv_reg mask, tmp, shift, dest; 34850b1347d2SRichard Henderson unsigned msb = 1U << (len - 1); 34860b1347d2SRichard Henderson 34870b1347d2SRichard Henderson if (c) { 34880b1347d2SRichard Henderson nullify_over(ctx); 34890b1347d2SRichard Henderson } 34900b1347d2SRichard Henderson 34910b1347d2SRichard Henderson dest = dest_gpr(ctx, rt); 34920b1347d2SRichard Henderson shift = tcg_temp_new(); 34930b1347d2SRichard Henderson tmp = tcg_temp_new(); 34940b1347d2SRichard Henderson 34950b1347d2SRichard Henderson /* Convert big-endian bit numbering in SAR to left-shift. */ 3496eaa3783bSRichard Henderson tcg_gen_xori_reg(shift, cpu_sar, TARGET_REGISTER_BITS - 1); 34970b1347d2SRichard Henderson 3498eaa3783bSRichard Henderson mask = tcg_const_reg(msb + (msb - 1)); 3499eaa3783bSRichard Henderson tcg_gen_and_reg(tmp, val, mask); 35000b1347d2SRichard Henderson if (rs) { 3501eaa3783bSRichard Henderson tcg_gen_shl_reg(mask, mask, shift); 3502eaa3783bSRichard Henderson tcg_gen_shl_reg(tmp, tmp, shift); 3503eaa3783bSRichard Henderson tcg_gen_andc_reg(dest, cpu_gr[rs], mask); 3504eaa3783bSRichard Henderson tcg_gen_or_reg(dest, dest, tmp); 35050b1347d2SRichard Henderson } else { 3506eaa3783bSRichard Henderson tcg_gen_shl_reg(dest, tmp, shift); 35070b1347d2SRichard Henderson } 35080b1347d2SRichard Henderson tcg_temp_free(shift); 35090b1347d2SRichard Henderson tcg_temp_free(mask); 35100b1347d2SRichard Henderson tcg_temp_free(tmp); 35110b1347d2SRichard Henderson save_gpr(ctx, rt, dest); 35120b1347d2SRichard Henderson 35130b1347d2SRichard Henderson /* Install the new nullification. */ 35140b1347d2SRichard Henderson cond_free(&ctx->null_cond); 35150b1347d2SRichard Henderson if (c) { 35160b1347d2SRichard Henderson ctx->null_cond = do_sed_cond(c, dest); 35170b1347d2SRichard Henderson } 351831234768SRichard Henderson return nullify_end(ctx); 35190b1347d2SRichard Henderson } 35200b1347d2SRichard Henderson 352130878590SRichard Henderson static bool trans_depw_sar(DisasContext *ctx, arg_depw_sar *a) 352230878590SRichard Henderson { 352330878590SRichard Henderson return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_gpr(ctx, a->r)); 352430878590SRichard Henderson } 352530878590SRichard Henderson 352630878590SRichard Henderson static bool trans_depwi_sar(DisasContext *ctx, arg_depwi_sar *a) 352730878590SRichard Henderson { 352830878590SRichard Henderson return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_const(ctx, a->i)); 352930878590SRichard Henderson } 35300b1347d2SRichard Henderson 3531*8340f534SRichard Henderson static bool trans_be(DisasContext *ctx, arg_be *a) 353298cd9ca7SRichard Henderson { 3533660eefe1SRichard Henderson TCGv_reg tmp; 353498cd9ca7SRichard Henderson 3535c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 353698cd9ca7SRichard Henderson /* ??? It seems like there should be a good way of using 353798cd9ca7SRichard Henderson "be disp(sr2, r0)", the canonical gateway entry mechanism 353898cd9ca7SRichard Henderson to our advantage. But that appears to be inconvenient to 353998cd9ca7SRichard Henderson manage along side branch delay slots. Therefore we handle 354098cd9ca7SRichard Henderson entry into the gateway page via absolute address. */ 354198cd9ca7SRichard Henderson /* Since we don't implement spaces, just branch. Do notice the special 354298cd9ca7SRichard Henderson case of "be disp(*,r0)" using a direct branch to disp, so that we can 354398cd9ca7SRichard Henderson goto_tb to the TB containing the syscall. */ 3544*8340f534SRichard Henderson if (a->b == 0) { 3545*8340f534SRichard Henderson return do_dbranch(ctx, a->disp, a->l, a->n); 354698cd9ca7SRichard Henderson } 3547c301f34eSRichard Henderson #else 3548c301f34eSRichard Henderson nullify_over(ctx); 3549660eefe1SRichard Henderson #endif 3550660eefe1SRichard Henderson 3551660eefe1SRichard Henderson tmp = get_temp(ctx); 3552*8340f534SRichard Henderson tcg_gen_addi_reg(tmp, load_gpr(ctx, a->b), a->disp); 3553660eefe1SRichard Henderson tmp = do_ibranch_priv(ctx, tmp); 3554c301f34eSRichard Henderson 3555c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 3556*8340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 3557c301f34eSRichard Henderson #else 3558c301f34eSRichard Henderson TCGv_i64 new_spc = tcg_temp_new_i64(); 3559c301f34eSRichard Henderson 3560*8340f534SRichard Henderson load_spr(ctx, new_spc, a->sp); 3561*8340f534SRichard Henderson if (a->l) { 3562c301f34eSRichard Henderson copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var); 3563c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f); 3564c301f34eSRichard Henderson } 3565*8340f534SRichard Henderson if (a->n && use_nullify_skip(ctx)) { 3566c301f34eSRichard Henderson tcg_gen_mov_reg(cpu_iaoq_f, tmp); 3567c301f34eSRichard Henderson tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4); 3568c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, new_spc); 3569c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, cpu_iasq_f); 3570c301f34eSRichard Henderson } else { 3571c301f34eSRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3572c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3573c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3574c301f34eSRichard Henderson } 3575c301f34eSRichard Henderson tcg_gen_mov_reg(cpu_iaoq_b, tmp); 3576c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, new_spc); 3577*8340f534SRichard Henderson nullify_set(ctx, a->n); 3578c301f34eSRichard Henderson } 3579c301f34eSRichard Henderson tcg_temp_free_i64(new_spc); 3580c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 358131234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 358231234768SRichard Henderson return nullify_end(ctx); 3583c301f34eSRichard Henderson #endif 358498cd9ca7SRichard Henderson } 358598cd9ca7SRichard Henderson 3586*8340f534SRichard Henderson static bool trans_bl(DisasContext *ctx, arg_bl *a) 358798cd9ca7SRichard Henderson { 3588*8340f534SRichard Henderson return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n); 358998cd9ca7SRichard Henderson } 359098cd9ca7SRichard Henderson 3591*8340f534SRichard Henderson static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a) 359243e05652SRichard Henderson { 3593*8340f534SRichard Henderson target_ureg dest = iaoq_dest(ctx, a->disp); 359443e05652SRichard Henderson 359543e05652SRichard Henderson /* Make sure the caller hasn't done something weird with the queue. 359643e05652SRichard Henderson * ??? This is not quite the same as the PSW[B] bit, which would be 359743e05652SRichard Henderson * expensive to track. Real hardware will trap for 359843e05652SRichard Henderson * b gateway 359943e05652SRichard Henderson * b gateway+4 (in delay slot of first branch) 360043e05652SRichard Henderson * However, checking for a non-sequential instruction queue *will* 360143e05652SRichard Henderson * diagnose the security hole 360243e05652SRichard Henderson * b gateway 360343e05652SRichard Henderson * b evil 360443e05652SRichard Henderson * in which instructions at evil would run with increased privs. 360543e05652SRichard Henderson */ 360643e05652SRichard Henderson if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) { 360743e05652SRichard Henderson return gen_illegal(ctx); 360843e05652SRichard Henderson } 360943e05652SRichard Henderson 361043e05652SRichard Henderson #ifndef CONFIG_USER_ONLY 361143e05652SRichard Henderson if (ctx->tb_flags & PSW_C) { 361243e05652SRichard Henderson CPUHPPAState *env = ctx->cs->env_ptr; 361343e05652SRichard Henderson int type = hppa_artype_for_page(env, ctx->base.pc_next); 361443e05652SRichard Henderson /* If we could not find a TLB entry, then we need to generate an 361543e05652SRichard Henderson ITLB miss exception so the kernel will provide it. 361643e05652SRichard Henderson The resulting TLB fill operation will invalidate this TB and 361743e05652SRichard Henderson we will re-translate, at which point we *will* be able to find 361843e05652SRichard Henderson the TLB entry and determine if this is in fact a gateway page. */ 361943e05652SRichard Henderson if (type < 0) { 362031234768SRichard Henderson gen_excp(ctx, EXCP_ITLB_MISS); 362131234768SRichard Henderson return true; 362243e05652SRichard Henderson } 362343e05652SRichard Henderson /* No change for non-gateway pages or for priv decrease. */ 362443e05652SRichard Henderson if (type >= 4 && type - 4 < ctx->privilege) { 362543e05652SRichard Henderson dest = deposit32(dest, 0, 2, type - 4); 362643e05652SRichard Henderson } 362743e05652SRichard Henderson } else { 362843e05652SRichard Henderson dest &= -4; /* priv = 0 */ 362943e05652SRichard Henderson } 363043e05652SRichard Henderson #endif 363143e05652SRichard Henderson 3632*8340f534SRichard Henderson return do_dbranch(ctx, dest, a->l, a->n); 363343e05652SRichard Henderson } 363443e05652SRichard Henderson 3635*8340f534SRichard Henderson static bool trans_blr(DisasContext *ctx, arg_blr *a) 363698cd9ca7SRichard Henderson { 3637eaa3783bSRichard Henderson TCGv_reg tmp = get_temp(ctx); 363898cd9ca7SRichard Henderson 3639*8340f534SRichard Henderson tcg_gen_shli_reg(tmp, load_gpr(ctx, a->x), 3); 3640eaa3783bSRichard Henderson tcg_gen_addi_reg(tmp, tmp, ctx->iaoq_f + 8); 3641660eefe1SRichard Henderson /* The computation here never changes privilege level. */ 3642*8340f534SRichard Henderson return do_ibranch(ctx, tmp, a->l, a->n); 364398cd9ca7SRichard Henderson } 364498cd9ca7SRichard Henderson 3645*8340f534SRichard Henderson static bool trans_bv(DisasContext *ctx, arg_bv *a) 364698cd9ca7SRichard Henderson { 3647eaa3783bSRichard Henderson TCGv_reg dest; 364898cd9ca7SRichard Henderson 3649*8340f534SRichard Henderson if (a->x == 0) { 3650*8340f534SRichard Henderson dest = load_gpr(ctx, a->b); 365198cd9ca7SRichard Henderson } else { 365298cd9ca7SRichard Henderson dest = get_temp(ctx); 3653*8340f534SRichard Henderson tcg_gen_shli_reg(dest, load_gpr(ctx, a->x), 3); 3654*8340f534SRichard Henderson tcg_gen_add_reg(dest, dest, load_gpr(ctx, a->b)); 365598cd9ca7SRichard Henderson } 3656660eefe1SRichard Henderson dest = do_ibranch_priv(ctx, dest); 3657*8340f534SRichard Henderson return do_ibranch(ctx, dest, 0, a->n); 365898cd9ca7SRichard Henderson } 365998cd9ca7SRichard Henderson 3660*8340f534SRichard Henderson static bool trans_bve(DisasContext *ctx, arg_bve *a) 366198cd9ca7SRichard Henderson { 3662660eefe1SRichard Henderson TCGv_reg dest; 366398cd9ca7SRichard Henderson 3664c301f34eSRichard Henderson #ifdef CONFIG_USER_ONLY 3665*8340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3666*8340f534SRichard Henderson return do_ibranch(ctx, dest, a->l, a->n); 3667c301f34eSRichard Henderson #else 3668c301f34eSRichard Henderson nullify_over(ctx); 3669*8340f534SRichard Henderson dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b)); 3670c301f34eSRichard Henderson 3671c301f34eSRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b); 3672c301f34eSRichard Henderson if (ctx->iaoq_b == -1) { 3673c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 3674c301f34eSRichard Henderson } 3675c301f34eSRichard Henderson copy_iaoq_entry(cpu_iaoq_b, -1, dest); 3676c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest)); 3677*8340f534SRichard Henderson if (a->l) { 3678*8340f534SRichard Henderson copy_iaoq_entry(cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var); 3679c301f34eSRichard Henderson } 3680*8340f534SRichard Henderson nullify_set(ctx, a->n); 3681c301f34eSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 368231234768SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 368331234768SRichard Henderson return nullify_end(ctx); 3684c301f34eSRichard Henderson #endif 368598cd9ca7SRichard Henderson } 368698cd9ca7SRichard Henderson 368731234768SRichard Henderson static bool trans_fop_wew_0c(DisasContext *ctx, uint32_t insn, 3688ebe9383cSRichard Henderson const DisasInsn *di) 3689ebe9383cSRichard Henderson { 3690ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3691ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 369231234768SRichard Henderson do_fop_wew(ctx, rt, ra, di->f.wew); 369331234768SRichard Henderson return true; 3694ebe9383cSRichard Henderson } 3695ebe9383cSRichard Henderson 369631234768SRichard Henderson static bool trans_fop_wew_0e(DisasContext *ctx, uint32_t insn, 3697ebe9383cSRichard Henderson const DisasInsn *di) 3698ebe9383cSRichard Henderson { 3699ebe9383cSRichard Henderson unsigned rt = assemble_rt64(insn); 3700ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 370131234768SRichard Henderson do_fop_wew(ctx, rt, ra, di->f.wew); 370231234768SRichard Henderson return true; 3703ebe9383cSRichard Henderson } 3704ebe9383cSRichard Henderson 370531234768SRichard Henderson static bool trans_fop_ded(DisasContext *ctx, uint32_t insn, 3706ebe9383cSRichard Henderson const DisasInsn *di) 3707ebe9383cSRichard Henderson { 3708ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3709ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 371031234768SRichard Henderson do_fop_ded(ctx, rt, ra, di->f.ded); 371131234768SRichard Henderson return true; 3712ebe9383cSRichard Henderson } 3713ebe9383cSRichard Henderson 371431234768SRichard Henderson static bool trans_fop_wed_0c(DisasContext *ctx, uint32_t insn, 3715ebe9383cSRichard Henderson const DisasInsn *di) 3716ebe9383cSRichard Henderson { 3717ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3718ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 371931234768SRichard Henderson do_fop_wed(ctx, rt, ra, di->f.wed); 372031234768SRichard Henderson return true; 3721ebe9383cSRichard Henderson } 3722ebe9383cSRichard Henderson 372331234768SRichard Henderson static bool trans_fop_wed_0e(DisasContext *ctx, uint32_t insn, 3724ebe9383cSRichard Henderson const DisasInsn *di) 3725ebe9383cSRichard Henderson { 3726ebe9383cSRichard Henderson unsigned rt = assemble_rt64(insn); 3727ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 372831234768SRichard Henderson do_fop_wed(ctx, rt, ra, di->f.wed); 372931234768SRichard Henderson return true; 3730ebe9383cSRichard Henderson } 3731ebe9383cSRichard Henderson 373231234768SRichard Henderson static bool trans_fop_dew_0c(DisasContext *ctx, uint32_t insn, 3733ebe9383cSRichard Henderson const DisasInsn *di) 3734ebe9383cSRichard Henderson { 3735ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3736ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 373731234768SRichard Henderson do_fop_dew(ctx, rt, ra, di->f.dew); 373831234768SRichard Henderson return true; 3739ebe9383cSRichard Henderson } 3740ebe9383cSRichard Henderson 374131234768SRichard Henderson static bool trans_fop_dew_0e(DisasContext *ctx, uint32_t insn, 3742ebe9383cSRichard Henderson const DisasInsn *di) 3743ebe9383cSRichard Henderson { 3744ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3745ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 374631234768SRichard Henderson do_fop_dew(ctx, rt, ra, di->f.dew); 374731234768SRichard Henderson return true; 3748ebe9383cSRichard Henderson } 3749ebe9383cSRichard Henderson 375031234768SRichard Henderson static bool trans_fop_weww_0c(DisasContext *ctx, uint32_t insn, 3751ebe9383cSRichard Henderson const DisasInsn *di) 3752ebe9383cSRichard Henderson { 3753ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3754ebe9383cSRichard Henderson unsigned rb = extract32(insn, 16, 5); 3755ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 375631234768SRichard Henderson do_fop_weww(ctx, rt, ra, rb, di->f.weww); 375731234768SRichard Henderson return true; 3758ebe9383cSRichard Henderson } 3759ebe9383cSRichard Henderson 376031234768SRichard Henderson static bool trans_fop_weww_0e(DisasContext *ctx, uint32_t insn, 3761ebe9383cSRichard Henderson const DisasInsn *di) 3762ebe9383cSRichard Henderson { 3763ebe9383cSRichard Henderson unsigned rt = assemble_rt64(insn); 3764ebe9383cSRichard Henderson unsigned rb = assemble_rb64(insn); 3765ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 376631234768SRichard Henderson do_fop_weww(ctx, rt, ra, rb, di->f.weww); 376731234768SRichard Henderson return true; 3768ebe9383cSRichard Henderson } 3769ebe9383cSRichard Henderson 377031234768SRichard Henderson static bool trans_fop_dedd(DisasContext *ctx, uint32_t insn, 3771ebe9383cSRichard Henderson const DisasInsn *di) 3772ebe9383cSRichard Henderson { 3773ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3774ebe9383cSRichard Henderson unsigned rb = extract32(insn, 16, 5); 3775ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 377631234768SRichard Henderson do_fop_dedd(ctx, rt, ra, rb, di->f.dedd); 377731234768SRichard Henderson return true; 3778ebe9383cSRichard Henderson } 3779ebe9383cSRichard Henderson 3780ebe9383cSRichard Henderson static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3781ebe9383cSRichard Henderson { 3782ebe9383cSRichard Henderson tcg_gen_mov_i32(dst, src); 3783ebe9383cSRichard Henderson } 3784ebe9383cSRichard Henderson 3785ebe9383cSRichard Henderson static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3786ebe9383cSRichard Henderson { 3787ebe9383cSRichard Henderson tcg_gen_mov_i64(dst, src); 3788ebe9383cSRichard Henderson } 3789ebe9383cSRichard Henderson 3790ebe9383cSRichard Henderson static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3791ebe9383cSRichard Henderson { 3792ebe9383cSRichard Henderson tcg_gen_andi_i32(dst, src, INT32_MAX); 3793ebe9383cSRichard Henderson } 3794ebe9383cSRichard Henderson 3795ebe9383cSRichard Henderson static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3796ebe9383cSRichard Henderson { 3797ebe9383cSRichard Henderson tcg_gen_andi_i64(dst, src, INT64_MAX); 3798ebe9383cSRichard Henderson } 3799ebe9383cSRichard Henderson 3800ebe9383cSRichard Henderson static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3801ebe9383cSRichard Henderson { 3802ebe9383cSRichard Henderson tcg_gen_xori_i32(dst, src, INT32_MIN); 3803ebe9383cSRichard Henderson } 3804ebe9383cSRichard Henderson 3805ebe9383cSRichard Henderson static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3806ebe9383cSRichard Henderson { 3807ebe9383cSRichard Henderson tcg_gen_xori_i64(dst, src, INT64_MIN); 3808ebe9383cSRichard Henderson } 3809ebe9383cSRichard Henderson 3810ebe9383cSRichard Henderson static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) 3811ebe9383cSRichard Henderson { 3812ebe9383cSRichard Henderson tcg_gen_ori_i32(dst, src, INT32_MIN); 3813ebe9383cSRichard Henderson } 3814ebe9383cSRichard Henderson 3815ebe9383cSRichard Henderson static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) 3816ebe9383cSRichard Henderson { 3817ebe9383cSRichard Henderson tcg_gen_ori_i64(dst, src, INT64_MIN); 3818ebe9383cSRichard Henderson } 3819ebe9383cSRichard Henderson 382031234768SRichard Henderson static void do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb, 3821ebe9383cSRichard Henderson unsigned y, unsigned c) 3822ebe9383cSRichard Henderson { 3823ebe9383cSRichard Henderson TCGv_i32 ta, tb, tc, ty; 3824ebe9383cSRichard Henderson 3825ebe9383cSRichard Henderson nullify_over(ctx); 3826ebe9383cSRichard Henderson 3827ebe9383cSRichard Henderson ta = load_frw0_i32(ra); 3828ebe9383cSRichard Henderson tb = load_frw0_i32(rb); 3829ebe9383cSRichard Henderson ty = tcg_const_i32(y); 3830ebe9383cSRichard Henderson tc = tcg_const_i32(c); 3831ebe9383cSRichard Henderson 3832ebe9383cSRichard Henderson gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc); 3833ebe9383cSRichard Henderson 3834ebe9383cSRichard Henderson tcg_temp_free_i32(ta); 3835ebe9383cSRichard Henderson tcg_temp_free_i32(tb); 3836ebe9383cSRichard Henderson tcg_temp_free_i32(ty); 3837ebe9383cSRichard Henderson tcg_temp_free_i32(tc); 3838ebe9383cSRichard Henderson 383931234768SRichard Henderson nullify_end(ctx); 3840ebe9383cSRichard Henderson } 3841ebe9383cSRichard Henderson 384231234768SRichard Henderson static bool trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn, 3843ebe9383cSRichard Henderson const DisasInsn *di) 3844ebe9383cSRichard Henderson { 3845ebe9383cSRichard Henderson unsigned c = extract32(insn, 0, 5); 3846ebe9383cSRichard Henderson unsigned y = extract32(insn, 13, 3); 3847ebe9383cSRichard Henderson unsigned rb = extract32(insn, 16, 5); 3848ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 384931234768SRichard Henderson do_fcmp_s(ctx, ra, rb, y, c); 385031234768SRichard Henderson return true; 3851ebe9383cSRichard Henderson } 3852ebe9383cSRichard Henderson 385331234768SRichard Henderson static bool trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn, 3854ebe9383cSRichard Henderson const DisasInsn *di) 3855ebe9383cSRichard Henderson { 3856ebe9383cSRichard Henderson unsigned c = extract32(insn, 0, 5); 3857ebe9383cSRichard Henderson unsigned y = extract32(insn, 13, 3); 3858ebe9383cSRichard Henderson unsigned rb = assemble_rb64(insn); 3859ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 386031234768SRichard Henderson do_fcmp_s(ctx, ra, rb, y, c); 386131234768SRichard Henderson return true; 3862ebe9383cSRichard Henderson } 3863ebe9383cSRichard Henderson 386431234768SRichard Henderson static bool trans_fcmp_d(DisasContext *ctx, uint32_t insn, const DisasInsn *di) 3865ebe9383cSRichard Henderson { 3866ebe9383cSRichard Henderson unsigned c = extract32(insn, 0, 5); 3867ebe9383cSRichard Henderson unsigned y = extract32(insn, 13, 3); 3868ebe9383cSRichard Henderson unsigned rb = extract32(insn, 16, 5); 3869ebe9383cSRichard Henderson unsigned ra = extract32(insn, 21, 5); 3870ebe9383cSRichard Henderson TCGv_i64 ta, tb; 3871ebe9383cSRichard Henderson TCGv_i32 tc, ty; 3872ebe9383cSRichard Henderson 3873ebe9383cSRichard Henderson nullify_over(ctx); 3874ebe9383cSRichard Henderson 3875ebe9383cSRichard Henderson ta = load_frd0(ra); 3876ebe9383cSRichard Henderson tb = load_frd0(rb); 3877ebe9383cSRichard Henderson ty = tcg_const_i32(y); 3878ebe9383cSRichard Henderson tc = tcg_const_i32(c); 3879ebe9383cSRichard Henderson 3880ebe9383cSRichard Henderson gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc); 3881ebe9383cSRichard Henderson 3882ebe9383cSRichard Henderson tcg_temp_free_i64(ta); 3883ebe9383cSRichard Henderson tcg_temp_free_i64(tb); 3884ebe9383cSRichard Henderson tcg_temp_free_i32(ty); 3885ebe9383cSRichard Henderson tcg_temp_free_i32(tc); 3886ebe9383cSRichard Henderson 388731234768SRichard Henderson return nullify_end(ctx); 3888ebe9383cSRichard Henderson } 3889ebe9383cSRichard Henderson 389031234768SRichard Henderson static bool trans_ftest_t(DisasContext *ctx, uint32_t insn, 3891ebe9383cSRichard Henderson const DisasInsn *di) 3892ebe9383cSRichard Henderson { 3893ebe9383cSRichard Henderson unsigned y = extract32(insn, 13, 3); 3894ebe9383cSRichard Henderson unsigned cbit = (y ^ 1) - 1; 3895eaa3783bSRichard Henderson TCGv_reg t; 3896ebe9383cSRichard Henderson 3897ebe9383cSRichard Henderson nullify_over(ctx); 3898ebe9383cSRichard Henderson 3899ebe9383cSRichard Henderson t = tcg_temp_new(); 3900eaa3783bSRichard Henderson tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow)); 3901eaa3783bSRichard Henderson tcg_gen_extract_reg(t, t, 21 - cbit, 1); 3902ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 3903ebe9383cSRichard Henderson tcg_temp_free(t); 3904ebe9383cSRichard Henderson 390531234768SRichard Henderson return nullify_end(ctx); 3906ebe9383cSRichard Henderson } 3907ebe9383cSRichard Henderson 390831234768SRichard Henderson static bool trans_ftest_q(DisasContext *ctx, uint32_t insn, 3909ebe9383cSRichard Henderson const DisasInsn *di) 3910ebe9383cSRichard Henderson { 3911ebe9383cSRichard Henderson unsigned c = extract32(insn, 0, 5); 3912ebe9383cSRichard Henderson int mask; 3913ebe9383cSRichard Henderson bool inv = false; 3914eaa3783bSRichard Henderson TCGv_reg t; 3915ebe9383cSRichard Henderson 3916ebe9383cSRichard Henderson nullify_over(ctx); 3917ebe9383cSRichard Henderson 3918ebe9383cSRichard Henderson t = tcg_temp_new(); 3919eaa3783bSRichard Henderson tcg_gen_ld32u_reg(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow)); 3920ebe9383cSRichard Henderson 3921ebe9383cSRichard Henderson switch (c) { 3922ebe9383cSRichard Henderson case 0: /* simple */ 3923eaa3783bSRichard Henderson tcg_gen_andi_reg(t, t, 0x4000000); 3924ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_NE, t); 3925ebe9383cSRichard Henderson goto done; 3926ebe9383cSRichard Henderson case 2: /* rej */ 3927ebe9383cSRichard Henderson inv = true; 3928ebe9383cSRichard Henderson /* fallthru */ 3929ebe9383cSRichard Henderson case 1: /* acc */ 3930ebe9383cSRichard Henderson mask = 0x43ff800; 3931ebe9383cSRichard Henderson break; 3932ebe9383cSRichard Henderson case 6: /* rej8 */ 3933ebe9383cSRichard Henderson inv = true; 3934ebe9383cSRichard Henderson /* fallthru */ 3935ebe9383cSRichard Henderson case 5: /* acc8 */ 3936ebe9383cSRichard Henderson mask = 0x43f8000; 3937ebe9383cSRichard Henderson break; 3938ebe9383cSRichard Henderson case 9: /* acc6 */ 3939ebe9383cSRichard Henderson mask = 0x43e0000; 3940ebe9383cSRichard Henderson break; 3941ebe9383cSRichard Henderson case 13: /* acc4 */ 3942ebe9383cSRichard Henderson mask = 0x4380000; 3943ebe9383cSRichard Henderson break; 3944ebe9383cSRichard Henderson case 17: /* acc2 */ 3945ebe9383cSRichard Henderson mask = 0x4200000; 3946ebe9383cSRichard Henderson break; 3947ebe9383cSRichard Henderson default: 3948ebe9383cSRichard Henderson return gen_illegal(ctx); 3949ebe9383cSRichard Henderson } 3950ebe9383cSRichard Henderson if (inv) { 3951eaa3783bSRichard Henderson TCGv_reg c = load_const(ctx, mask); 3952eaa3783bSRichard Henderson tcg_gen_or_reg(t, t, c); 3953ebe9383cSRichard Henderson ctx->null_cond = cond_make(TCG_COND_EQ, t, c); 3954ebe9383cSRichard Henderson } else { 3955eaa3783bSRichard Henderson tcg_gen_andi_reg(t, t, mask); 3956ebe9383cSRichard Henderson ctx->null_cond = cond_make_0(TCG_COND_EQ, t); 3957ebe9383cSRichard Henderson } 3958ebe9383cSRichard Henderson done: 395931234768SRichard Henderson return nullify_end(ctx); 3960ebe9383cSRichard Henderson } 3961ebe9383cSRichard Henderson 396231234768SRichard Henderson static bool trans_xmpyu(DisasContext *ctx, uint32_t insn, const DisasInsn *di) 3963ebe9383cSRichard Henderson { 3964ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 3965ebe9383cSRichard Henderson unsigned rb = assemble_rb64(insn); 3966ebe9383cSRichard Henderson unsigned ra = assemble_ra64(insn); 3967ebe9383cSRichard Henderson TCGv_i64 a, b; 3968ebe9383cSRichard Henderson 3969ebe9383cSRichard Henderson nullify_over(ctx); 3970ebe9383cSRichard Henderson 3971ebe9383cSRichard Henderson a = load_frw0_i64(ra); 3972ebe9383cSRichard Henderson b = load_frw0_i64(rb); 3973ebe9383cSRichard Henderson tcg_gen_mul_i64(a, a, b); 3974ebe9383cSRichard Henderson save_frd(rt, a); 3975ebe9383cSRichard Henderson tcg_temp_free_i64(a); 3976ebe9383cSRichard Henderson tcg_temp_free_i64(b); 3977ebe9383cSRichard Henderson 397831234768SRichard Henderson return nullify_end(ctx); 3979ebe9383cSRichard Henderson } 3980ebe9383cSRichard Henderson 3981eff235ebSPaolo Bonzini #define FOP_DED trans_fop_ded, .f.ded 3982eff235ebSPaolo Bonzini #define FOP_DEDD trans_fop_dedd, .f.dedd 3983ebe9383cSRichard Henderson 3984eff235ebSPaolo Bonzini #define FOP_WEW trans_fop_wew_0c, .f.wew 3985eff235ebSPaolo Bonzini #define FOP_DEW trans_fop_dew_0c, .f.dew 3986eff235ebSPaolo Bonzini #define FOP_WED trans_fop_wed_0c, .f.wed 3987eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0c, .f.weww 3988ebe9383cSRichard Henderson 3989ebe9383cSRichard Henderson static const DisasInsn table_float_0c[] = { 3990ebe9383cSRichard Henderson /* floating point class zero */ 3991ebe9383cSRichard Henderson { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s }, 3992ebe9383cSRichard Henderson { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s }, 3993ebe9383cSRichard Henderson { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s }, 3994ebe9383cSRichard Henderson { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s }, 3995ebe9383cSRichard Henderson { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s }, 3996ebe9383cSRichard Henderson { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s }, 3997ebe9383cSRichard Henderson 3998ebe9383cSRichard Henderson { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d }, 3999ebe9383cSRichard Henderson { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d }, 4000ebe9383cSRichard Henderson { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d }, 4001ebe9383cSRichard Henderson { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d }, 4002ebe9383cSRichard Henderson { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d }, 4003ebe9383cSRichard Henderson { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d }, 4004ebe9383cSRichard Henderson 4005ebe9383cSRichard Henderson /* floating point class three */ 4006ebe9383cSRichard Henderson { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s }, 4007ebe9383cSRichard Henderson { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s }, 4008ebe9383cSRichard Henderson { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s }, 4009ebe9383cSRichard Henderson { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s }, 4010ebe9383cSRichard Henderson 4011ebe9383cSRichard Henderson { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d }, 4012ebe9383cSRichard Henderson { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d }, 4013ebe9383cSRichard Henderson { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d }, 4014ebe9383cSRichard Henderson { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d }, 4015ebe9383cSRichard Henderson 4016ebe9383cSRichard Henderson /* floating point class one */ 4017ebe9383cSRichard Henderson /* float/float */ 4018ebe9383cSRichard Henderson { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s }, 4019ebe9383cSRichard Henderson { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d }, 4020ebe9383cSRichard Henderson /* int/float */ 4021ebe9383cSRichard Henderson { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s }, 4022ebe9383cSRichard Henderson { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s }, 4023ebe9383cSRichard Henderson { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d }, 4024ebe9383cSRichard Henderson { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d }, 4025ebe9383cSRichard Henderson /* float/int */ 4026ebe9383cSRichard Henderson { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w }, 4027ebe9383cSRichard Henderson { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w }, 4028ebe9383cSRichard Henderson { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw }, 4029ebe9383cSRichard Henderson { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw }, 4030ebe9383cSRichard Henderson /* float/int truncate */ 4031ebe9383cSRichard Henderson { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w }, 4032ebe9383cSRichard Henderson { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w }, 4033ebe9383cSRichard Henderson { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw }, 4034ebe9383cSRichard Henderson { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw }, 4035ebe9383cSRichard Henderson /* uint/float */ 4036ebe9383cSRichard Henderson { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s }, 4037ebe9383cSRichard Henderson { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s }, 4038ebe9383cSRichard Henderson { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d }, 4039ebe9383cSRichard Henderson { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d }, 4040ebe9383cSRichard Henderson /* float/uint */ 4041ebe9383cSRichard Henderson { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw }, 4042ebe9383cSRichard Henderson { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw }, 4043ebe9383cSRichard Henderson { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw }, 4044ebe9383cSRichard Henderson { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw }, 4045ebe9383cSRichard Henderson /* float/uint truncate */ 4046ebe9383cSRichard Henderson { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw }, 4047ebe9383cSRichard Henderson { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw }, 4048ebe9383cSRichard Henderson { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw }, 4049ebe9383cSRichard Henderson { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw }, 4050ebe9383cSRichard Henderson 4051ebe9383cSRichard Henderson /* floating point class two */ 4052ebe9383cSRichard Henderson { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c }, 4053ebe9383cSRichard Henderson { 0x30000c00, 0xfc001fe0, trans_fcmp_d }, 4054ebe9383cSRichard Henderson { 0x30002420, 0xffffffe0, trans_ftest_q }, 4055ebe9383cSRichard Henderson { 0x30000420, 0xffff1fff, trans_ftest_t }, 4056ebe9383cSRichard Henderson 4057ebe9383cSRichard Henderson /* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0. 4058ebe9383cSRichard Henderson This is machine/revision == 0, which is reserved for simulator. */ 4059ebe9383cSRichard Henderson { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s }, 4060ebe9383cSRichard Henderson }; 4061ebe9383cSRichard Henderson 4062ebe9383cSRichard Henderson #undef FOP_WEW 4063ebe9383cSRichard Henderson #undef FOP_DEW 4064ebe9383cSRichard Henderson #undef FOP_WED 4065ebe9383cSRichard Henderson #undef FOP_WEWW 4066eff235ebSPaolo Bonzini #define FOP_WEW trans_fop_wew_0e, .f.wew 4067eff235ebSPaolo Bonzini #define FOP_DEW trans_fop_dew_0e, .f.dew 4068eff235ebSPaolo Bonzini #define FOP_WED trans_fop_wed_0e, .f.wed 4069eff235ebSPaolo Bonzini #define FOP_WEWW trans_fop_weww_0e, .f.weww 4070ebe9383cSRichard Henderson 4071ebe9383cSRichard Henderson static const DisasInsn table_float_0e[] = { 4072ebe9383cSRichard Henderson /* floating point class zero */ 4073ebe9383cSRichard Henderson { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s }, 4074ebe9383cSRichard Henderson { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s }, 4075ebe9383cSRichard Henderson { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s }, 4076ebe9383cSRichard Henderson { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s }, 4077ebe9383cSRichard Henderson { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s }, 4078ebe9383cSRichard Henderson { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s }, 4079ebe9383cSRichard Henderson 4080ebe9383cSRichard Henderson { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d }, 4081ebe9383cSRichard Henderson { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d }, 4082ebe9383cSRichard Henderson { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d }, 4083ebe9383cSRichard Henderson { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d }, 4084ebe9383cSRichard Henderson { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d }, 4085ebe9383cSRichard Henderson { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d }, 4086ebe9383cSRichard Henderson 4087ebe9383cSRichard Henderson /* floating point class three */ 4088ebe9383cSRichard Henderson { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s }, 4089ebe9383cSRichard Henderson { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s }, 4090ebe9383cSRichard Henderson { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s }, 4091ebe9383cSRichard Henderson { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s }, 4092ebe9383cSRichard Henderson 4093ebe9383cSRichard Henderson { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d }, 4094ebe9383cSRichard Henderson { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d }, 4095ebe9383cSRichard Henderson { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d }, 4096ebe9383cSRichard Henderson { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d }, 4097ebe9383cSRichard Henderson 4098ebe9383cSRichard Henderson { 0x38004700, 0xfc00ef60, trans_xmpyu }, 4099ebe9383cSRichard Henderson 4100ebe9383cSRichard Henderson /* floating point class one */ 4101ebe9383cSRichard Henderson /* float/float */ 4102ebe9383cSRichard Henderson { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s }, 4103fe0a69ccSRichard Henderson { 0x38002200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_d }, 4104ebe9383cSRichard Henderson /* int/float */ 4105fe0a69ccSRichard Henderson { 0x38008200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_w_s }, 4106ebe9383cSRichard Henderson { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s }, 4107ebe9383cSRichard Henderson { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d }, 4108ebe9383cSRichard Henderson { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d }, 4109ebe9383cSRichard Henderson /* float/int */ 4110fe0a69ccSRichard Henderson { 0x38010200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_s_w }, 4111ebe9383cSRichard Henderson { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w }, 4112ebe9383cSRichard Henderson { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw }, 4113ebe9383cSRichard Henderson { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw }, 4114ebe9383cSRichard Henderson /* float/int truncate */ 4115fe0a69ccSRichard Henderson { 0x38018200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_t_s_w }, 4116ebe9383cSRichard Henderson { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w }, 4117ebe9383cSRichard Henderson { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw }, 4118ebe9383cSRichard Henderson { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw }, 4119ebe9383cSRichard Henderson /* uint/float */ 4120fe0a69ccSRichard Henderson { 0x38028200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_uw_s }, 4121ebe9383cSRichard Henderson { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s }, 4122ebe9383cSRichard Henderson { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d }, 4123ebe9383cSRichard Henderson { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d }, 4124ebe9383cSRichard Henderson /* float/uint */ 4125fe0a69ccSRichard Henderson { 0x38030200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_s_uw }, 4126ebe9383cSRichard Henderson { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw }, 4127ebe9383cSRichard Henderson { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw }, 4128ebe9383cSRichard Henderson { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw }, 4129ebe9383cSRichard Henderson /* float/uint truncate */ 4130fe0a69ccSRichard Henderson { 0x38038200, 0xfc1ffe20, FOP_WEW = gen_helper_fcnv_t_s_uw }, 4131ebe9383cSRichard Henderson { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw }, 4132ebe9383cSRichard Henderson { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw }, 4133ebe9383cSRichard Henderson { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw }, 4134ebe9383cSRichard Henderson 4135ebe9383cSRichard Henderson /* floating point class two */ 4136ebe9383cSRichard Henderson { 0x38000400, 0xfc000f60, trans_fcmp_s_0e }, 4137ebe9383cSRichard Henderson { 0x38000c00, 0xfc001fe0, trans_fcmp_d }, 4138ebe9383cSRichard Henderson }; 4139ebe9383cSRichard Henderson 4140ebe9383cSRichard Henderson #undef FOP_WEW 4141ebe9383cSRichard Henderson #undef FOP_DEW 4142ebe9383cSRichard Henderson #undef FOP_WED 4143ebe9383cSRichard Henderson #undef FOP_WEWW 4144ebe9383cSRichard Henderson #undef FOP_DED 4145ebe9383cSRichard Henderson #undef FOP_DEDD 4146ebe9383cSRichard Henderson 4147ebe9383cSRichard Henderson /* Convert the fmpyadd single-precision register encodings to standard. */ 4148ebe9383cSRichard Henderson static inline int fmpyadd_s_reg(unsigned r) 4149ebe9383cSRichard Henderson { 4150ebe9383cSRichard Henderson return (r & 16) * 2 + 16 + (r & 15); 4151ebe9383cSRichard Henderson } 4152ebe9383cSRichard Henderson 4153b1e2af57SRichard Henderson static bool do_fmpyadd_s(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4154ebe9383cSRichard Henderson { 4155b1e2af57SRichard Henderson int tm = fmpyadd_s_reg(a->tm); 4156b1e2af57SRichard Henderson int ra = fmpyadd_s_reg(a->ra); 4157b1e2af57SRichard Henderson int ta = fmpyadd_s_reg(a->ta); 4158b1e2af57SRichard Henderson int rm2 = fmpyadd_s_reg(a->rm2); 4159b1e2af57SRichard Henderson int rm1 = fmpyadd_s_reg(a->rm1); 4160ebe9383cSRichard Henderson 4161ebe9383cSRichard Henderson nullify_over(ctx); 4162ebe9383cSRichard Henderson 4163ebe9383cSRichard Henderson do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); 4164ebe9383cSRichard Henderson do_fop_weww(ctx, ta, ta, ra, 4165ebe9383cSRichard Henderson is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); 4166ebe9383cSRichard Henderson 416731234768SRichard Henderson return nullify_end(ctx); 4168ebe9383cSRichard Henderson } 4169ebe9383cSRichard Henderson 4170b1e2af57SRichard Henderson static bool trans_fmpyadd_f(DisasContext *ctx, arg_mpyadd *a) 4171b1e2af57SRichard Henderson { 4172b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, false); 4173b1e2af57SRichard Henderson } 4174b1e2af57SRichard Henderson 4175b1e2af57SRichard Henderson static bool trans_fmpysub_f(DisasContext *ctx, arg_mpyadd *a) 4176b1e2af57SRichard Henderson { 4177b1e2af57SRichard Henderson return do_fmpyadd_s(ctx, a, true); 4178b1e2af57SRichard Henderson } 4179b1e2af57SRichard Henderson 4180b1e2af57SRichard Henderson static bool do_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a, bool is_sub) 4181b1e2af57SRichard Henderson { 4182b1e2af57SRichard Henderson nullify_over(ctx); 4183b1e2af57SRichard Henderson 4184b1e2af57SRichard Henderson do_fop_dedd(ctx, a->tm, a->rm1, a->rm2, gen_helper_fmpy_d); 4185b1e2af57SRichard Henderson do_fop_dedd(ctx, a->ta, a->ta, a->ra, 4186b1e2af57SRichard Henderson is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); 4187b1e2af57SRichard Henderson 4188b1e2af57SRichard Henderson return nullify_end(ctx); 4189b1e2af57SRichard Henderson } 4190b1e2af57SRichard Henderson 4191b1e2af57SRichard Henderson static bool trans_fmpyadd_d(DisasContext *ctx, arg_mpyadd *a) 4192b1e2af57SRichard Henderson { 4193b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, false); 4194b1e2af57SRichard Henderson } 4195b1e2af57SRichard Henderson 4196b1e2af57SRichard Henderson static bool trans_fmpysub_d(DisasContext *ctx, arg_mpyadd *a) 4197b1e2af57SRichard Henderson { 4198b1e2af57SRichard Henderson return do_fmpyadd_d(ctx, a, true); 4199b1e2af57SRichard Henderson } 4200b1e2af57SRichard Henderson 420131234768SRichard Henderson static bool trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn, 4202ebe9383cSRichard Henderson const DisasInsn *di) 4203ebe9383cSRichard Henderson { 4204ebe9383cSRichard Henderson unsigned rt = assemble_rt64(insn); 4205ebe9383cSRichard Henderson unsigned neg = extract32(insn, 5, 1); 4206ebe9383cSRichard Henderson unsigned rm1 = assemble_ra64(insn); 4207ebe9383cSRichard Henderson unsigned rm2 = assemble_rb64(insn); 4208ebe9383cSRichard Henderson unsigned ra3 = assemble_rc64(insn); 4209ebe9383cSRichard Henderson TCGv_i32 a, b, c; 4210ebe9383cSRichard Henderson 4211ebe9383cSRichard Henderson nullify_over(ctx); 4212ebe9383cSRichard Henderson a = load_frw0_i32(rm1); 4213ebe9383cSRichard Henderson b = load_frw0_i32(rm2); 4214ebe9383cSRichard Henderson c = load_frw0_i32(ra3); 4215ebe9383cSRichard Henderson 4216ebe9383cSRichard Henderson if (neg) { 4217ebe9383cSRichard Henderson gen_helper_fmpynfadd_s(a, cpu_env, a, b, c); 4218ebe9383cSRichard Henderson } else { 4219ebe9383cSRichard Henderson gen_helper_fmpyfadd_s(a, cpu_env, a, b, c); 4220ebe9383cSRichard Henderson } 4221ebe9383cSRichard Henderson 4222ebe9383cSRichard Henderson tcg_temp_free_i32(b); 4223ebe9383cSRichard Henderson tcg_temp_free_i32(c); 4224ebe9383cSRichard Henderson save_frw_i32(rt, a); 4225ebe9383cSRichard Henderson tcg_temp_free_i32(a); 422631234768SRichard Henderson return nullify_end(ctx); 4227ebe9383cSRichard Henderson } 4228ebe9383cSRichard Henderson 422931234768SRichard Henderson static bool trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn, 4230ebe9383cSRichard Henderson const DisasInsn *di) 4231ebe9383cSRichard Henderson { 4232ebe9383cSRichard Henderson unsigned rt = extract32(insn, 0, 5); 4233ebe9383cSRichard Henderson unsigned neg = extract32(insn, 5, 1); 4234ebe9383cSRichard Henderson unsigned rm1 = extract32(insn, 21, 5); 4235ebe9383cSRichard Henderson unsigned rm2 = extract32(insn, 16, 5); 4236ebe9383cSRichard Henderson unsigned ra3 = assemble_rc64(insn); 4237ebe9383cSRichard Henderson TCGv_i64 a, b, c; 4238ebe9383cSRichard Henderson 4239ebe9383cSRichard Henderson nullify_over(ctx); 4240ebe9383cSRichard Henderson a = load_frd0(rm1); 4241ebe9383cSRichard Henderson b = load_frd0(rm2); 4242ebe9383cSRichard Henderson c = load_frd0(ra3); 4243ebe9383cSRichard Henderson 4244ebe9383cSRichard Henderson if (neg) { 4245ebe9383cSRichard Henderson gen_helper_fmpynfadd_d(a, cpu_env, a, b, c); 4246ebe9383cSRichard Henderson } else { 4247ebe9383cSRichard Henderson gen_helper_fmpyfadd_d(a, cpu_env, a, b, c); 4248ebe9383cSRichard Henderson } 4249ebe9383cSRichard Henderson 4250ebe9383cSRichard Henderson tcg_temp_free_i64(b); 4251ebe9383cSRichard Henderson tcg_temp_free_i64(c); 4252ebe9383cSRichard Henderson save_frd(rt, a); 4253ebe9383cSRichard Henderson tcg_temp_free_i64(a); 425431234768SRichard Henderson return nullify_end(ctx); 4255ebe9383cSRichard Henderson } 4256ebe9383cSRichard Henderson 4257ebe9383cSRichard Henderson static const DisasInsn table_fp_fused[] = { 4258ebe9383cSRichard Henderson { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s }, 4259ebe9383cSRichard Henderson { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d } 4260ebe9383cSRichard Henderson }; 4261ebe9383cSRichard Henderson 426231234768SRichard Henderson static void translate_table_int(DisasContext *ctx, uint32_t insn, 426361766fe9SRichard Henderson const DisasInsn table[], size_t n) 426461766fe9SRichard Henderson { 426561766fe9SRichard Henderson size_t i; 426661766fe9SRichard Henderson for (i = 0; i < n; ++i) { 426761766fe9SRichard Henderson if ((insn & table[i].mask) == table[i].insn) { 426831234768SRichard Henderson table[i].trans(ctx, insn, &table[i]); 426931234768SRichard Henderson return; 427061766fe9SRichard Henderson } 427161766fe9SRichard Henderson } 4272b36942a6SRichard Henderson qemu_log_mask(LOG_UNIMP, "UNIMP insn %08x @ " TARGET_FMT_lx "\n", 4273b36942a6SRichard Henderson insn, ctx->base.pc_next); 427431234768SRichard Henderson gen_illegal(ctx); 427561766fe9SRichard Henderson } 427661766fe9SRichard Henderson 427761766fe9SRichard Henderson #define translate_table(ctx, insn, table) \ 427861766fe9SRichard Henderson translate_table_int(ctx, insn, table, ARRAY_SIZE(table)) 427961766fe9SRichard Henderson 428031234768SRichard Henderson static void translate_one(DisasContext *ctx, uint32_t insn) 428161766fe9SRichard Henderson { 428240f9f908SRichard Henderson uint32_t opc; 428361766fe9SRichard Henderson 428440f9f908SRichard Henderson /* Transition to the auto-generated decoder. */ 428540f9f908SRichard Henderson if (decode(ctx, insn)) { 428640f9f908SRichard Henderson return; 428740f9f908SRichard Henderson } 428840f9f908SRichard Henderson 428940f9f908SRichard Henderson opc = extract32(insn, 26, 6); 429061766fe9SRichard Henderson switch (opc) { 4291b2167459SRichard Henderson case 0x08: 429231234768SRichard Henderson trans_ldil(ctx, insn); 429331234768SRichard Henderson return; 429496d6407fSRichard Henderson case 0x09: 429531234768SRichard Henderson trans_copr_w(ctx, insn); 429631234768SRichard Henderson return; 4297b2167459SRichard Henderson case 0x0A: 429831234768SRichard Henderson trans_addil(ctx, insn); 429931234768SRichard Henderson return; 430096d6407fSRichard Henderson case 0x0B: 430131234768SRichard Henderson trans_copr_dw(ctx, insn); 430231234768SRichard Henderson return; 4303ebe9383cSRichard Henderson case 0x0C: 430431234768SRichard Henderson translate_table(ctx, insn, table_float_0c); 430531234768SRichard Henderson return; 4306b2167459SRichard Henderson case 0x0D: 430731234768SRichard Henderson trans_ldo(ctx, insn); 430831234768SRichard Henderson return; 4309ebe9383cSRichard Henderson case 0x0E: 431031234768SRichard Henderson translate_table(ctx, insn, table_float_0e); 431131234768SRichard Henderson return; 431296d6407fSRichard Henderson 431396d6407fSRichard Henderson case 0x10: 431431234768SRichard Henderson trans_load(ctx, insn, false, MO_UB); 431531234768SRichard Henderson return; 431696d6407fSRichard Henderson case 0x11: 431731234768SRichard Henderson trans_load(ctx, insn, false, MO_TEUW); 431831234768SRichard Henderson return; 431996d6407fSRichard Henderson case 0x12: 432031234768SRichard Henderson trans_load(ctx, insn, false, MO_TEUL); 432131234768SRichard Henderson return; 432296d6407fSRichard Henderson case 0x13: 432331234768SRichard Henderson trans_load(ctx, insn, true, MO_TEUL); 432431234768SRichard Henderson return; 432596d6407fSRichard Henderson case 0x16: 432631234768SRichard Henderson trans_fload_mod(ctx, insn); 432731234768SRichard Henderson return; 432896d6407fSRichard Henderson case 0x17: 432931234768SRichard Henderson trans_load_w(ctx, insn); 433031234768SRichard Henderson return; 433196d6407fSRichard Henderson case 0x18: 433231234768SRichard Henderson trans_store(ctx, insn, false, MO_UB); 433331234768SRichard Henderson return; 433496d6407fSRichard Henderson case 0x19: 433531234768SRichard Henderson trans_store(ctx, insn, false, MO_TEUW); 433631234768SRichard Henderson return; 433796d6407fSRichard Henderson case 0x1A: 433831234768SRichard Henderson trans_store(ctx, insn, false, MO_TEUL); 433931234768SRichard Henderson return; 434096d6407fSRichard Henderson case 0x1B: 434131234768SRichard Henderson trans_store(ctx, insn, true, MO_TEUL); 434231234768SRichard Henderson return; 434396d6407fSRichard Henderson case 0x1E: 434431234768SRichard Henderson trans_fstore_mod(ctx, insn); 434531234768SRichard Henderson return; 434696d6407fSRichard Henderson case 0x1F: 434731234768SRichard Henderson trans_store_w(ctx, insn); 434831234768SRichard Henderson return; 434996d6407fSRichard Henderson 4350b2167459SRichard Henderson case 0x24: 435131234768SRichard Henderson trans_cmpiclr(ctx, insn); 435231234768SRichard Henderson return; 4353b2167459SRichard Henderson case 0x25: 435431234768SRichard Henderson trans_subi(ctx, insn); 435531234768SRichard Henderson return; 4356b2167459SRichard Henderson case 0x2C: 4357b2167459SRichard Henderson case 0x2D: 435831234768SRichard Henderson trans_addi(ctx, insn); 435931234768SRichard Henderson return; 4360ebe9383cSRichard Henderson case 0x2E: 436131234768SRichard Henderson translate_table(ctx, insn, table_fp_fused); 436231234768SRichard Henderson return; 436396d6407fSRichard Henderson 436496d6407fSRichard Henderson case 0x04: /* spopn */ 436596d6407fSRichard Henderson case 0x05: /* diag */ 436696d6407fSRichard Henderson case 0x0F: /* product specific */ 436796d6407fSRichard Henderson break; 436896d6407fSRichard Henderson 436996d6407fSRichard Henderson case 0x07: /* unassigned */ 437096d6407fSRichard Henderson case 0x15: /* unassigned */ 437196d6407fSRichard Henderson case 0x1D: /* unassigned */ 437296d6407fSRichard Henderson case 0x37: /* unassigned */ 43736210db05SHelge Deller break; 43746210db05SHelge Deller case 0x3F: 43756210db05SHelge Deller #ifndef CONFIG_USER_ONLY 43766210db05SHelge Deller /* Unassigned, but use as system-halt. */ 43776210db05SHelge Deller if (insn == 0xfffdead0) { 437831234768SRichard Henderson gen_hlt(ctx, 0); /* halt system */ 437931234768SRichard Henderson return; 43806210db05SHelge Deller } 43816210db05SHelge Deller if (insn == 0xfffdead1) { 438231234768SRichard Henderson gen_hlt(ctx, 1); /* reset system */ 438331234768SRichard Henderson return; 43846210db05SHelge Deller } 43856210db05SHelge Deller #endif 43866210db05SHelge Deller break; 438761766fe9SRichard Henderson default: 438861766fe9SRichard Henderson break; 438961766fe9SRichard Henderson } 439031234768SRichard Henderson gen_illegal(ctx); 439161766fe9SRichard Henderson } 439261766fe9SRichard Henderson 4393b542683dSEmilio G. Cota static void hppa_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 439461766fe9SRichard Henderson { 439551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4396f764718dSRichard Henderson int bound; 439761766fe9SRichard Henderson 439851b061fbSRichard Henderson ctx->cs = cs; 4399494737b7SRichard Henderson ctx->tb_flags = ctx->base.tb->flags; 44003d68ee7bSRichard Henderson 44013d68ee7bSRichard Henderson #ifdef CONFIG_USER_ONLY 44023d68ee7bSRichard Henderson ctx->privilege = MMU_USER_IDX; 44033d68ee7bSRichard Henderson ctx->mmu_idx = MMU_USER_IDX; 4404ebd0e151SRichard Henderson ctx->iaoq_f = ctx->base.pc_first | MMU_USER_IDX; 4405ebd0e151SRichard Henderson ctx->iaoq_b = ctx->base.tb->cs_base | MMU_USER_IDX; 4406c301f34eSRichard Henderson #else 4407494737b7SRichard Henderson ctx->privilege = (ctx->tb_flags >> TB_FLAG_PRIV_SHIFT) & 3; 4408494737b7SRichard Henderson ctx->mmu_idx = (ctx->tb_flags & PSW_D ? ctx->privilege : MMU_PHYS_IDX); 44093d68ee7bSRichard Henderson 4410c301f34eSRichard Henderson /* Recover the IAOQ values from the GVA + PRIV. */ 4411c301f34eSRichard Henderson uint64_t cs_base = ctx->base.tb->cs_base; 4412c301f34eSRichard Henderson uint64_t iasq_f = cs_base & ~0xffffffffull; 4413c301f34eSRichard Henderson int32_t diff = cs_base; 4414c301f34eSRichard Henderson 4415c301f34eSRichard Henderson ctx->iaoq_f = (ctx->base.pc_first & ~iasq_f) + ctx->privilege; 4416c301f34eSRichard Henderson ctx->iaoq_b = (diff ? ctx->iaoq_f + diff : -1); 4417c301f34eSRichard Henderson #endif 441851b061fbSRichard Henderson ctx->iaoq_n = -1; 4419f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 442061766fe9SRichard Henderson 44213d68ee7bSRichard Henderson /* Bound the number of instructions by those left on the page. */ 44223d68ee7bSRichard Henderson bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; 4423b542683dSEmilio G. Cota ctx->base.max_insns = MIN(ctx->base.max_insns, bound); 44243d68ee7bSRichard Henderson 442586f8d05fSRichard Henderson ctx->ntempr = 0; 442686f8d05fSRichard Henderson ctx->ntempl = 0; 442786f8d05fSRichard Henderson memset(ctx->tempr, 0, sizeof(ctx->tempr)); 442886f8d05fSRichard Henderson memset(ctx->templ, 0, sizeof(ctx->templ)); 442961766fe9SRichard Henderson } 443061766fe9SRichard Henderson 443151b061fbSRichard Henderson static void hppa_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) 443251b061fbSRichard Henderson { 443351b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 443461766fe9SRichard Henderson 44353d68ee7bSRichard Henderson /* Seed the nullification status from PSW[N], as saved in TB->FLAGS. */ 443651b061fbSRichard Henderson ctx->null_cond = cond_make_f(); 443751b061fbSRichard Henderson ctx->psw_n_nonzero = false; 4438494737b7SRichard Henderson if (ctx->tb_flags & PSW_N) { 443951b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_ALWAYS; 444051b061fbSRichard Henderson ctx->psw_n_nonzero = true; 4441129e9cc3SRichard Henderson } 444251b061fbSRichard Henderson ctx->null_lab = NULL; 444361766fe9SRichard Henderson } 444461766fe9SRichard Henderson 444551b061fbSRichard Henderson static void hppa_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 444651b061fbSRichard Henderson { 444751b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 444851b061fbSRichard Henderson 444951b061fbSRichard Henderson tcg_gen_insn_start(ctx->iaoq_f, ctx->iaoq_b); 445051b061fbSRichard Henderson } 445151b061fbSRichard Henderson 445251b061fbSRichard Henderson static bool hppa_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, 445351b061fbSRichard Henderson const CPUBreakpoint *bp) 445451b061fbSRichard Henderson { 445551b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 445651b061fbSRichard Henderson 445731234768SRichard Henderson gen_excp(ctx, EXCP_DEBUG); 4458c301f34eSRichard Henderson ctx->base.pc_next += 4; 445951b061fbSRichard Henderson return true; 446051b061fbSRichard Henderson } 446151b061fbSRichard Henderson 446251b061fbSRichard Henderson static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 446351b061fbSRichard Henderson { 446451b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 446551b061fbSRichard Henderson CPUHPPAState *env = cs->env_ptr; 446651b061fbSRichard Henderson DisasJumpType ret; 446751b061fbSRichard Henderson int i, n; 446851b061fbSRichard Henderson 446951b061fbSRichard Henderson /* Execute one insn. */ 4470ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4471c301f34eSRichard Henderson if (ctx->base.pc_next < TARGET_PAGE_SIZE) { 447231234768SRichard Henderson do_page_zero(ctx); 447331234768SRichard Henderson ret = ctx->base.is_jmp; 4474869051eaSRichard Henderson assert(ret != DISAS_NEXT); 4475ba1d0b44SRichard Henderson } else 4476ba1d0b44SRichard Henderson #endif 4477ba1d0b44SRichard Henderson { 447861766fe9SRichard Henderson /* Always fetch the insn, even if nullified, so that we check 447961766fe9SRichard Henderson the page permissions for execute. */ 4480c301f34eSRichard Henderson uint32_t insn = cpu_ldl_code(env, ctx->base.pc_next); 448161766fe9SRichard Henderson 448261766fe9SRichard Henderson /* Set up the IA queue for the next insn. 448361766fe9SRichard Henderson This will be overwritten by a branch. */ 448451b061fbSRichard Henderson if (ctx->iaoq_b == -1) { 448551b061fbSRichard Henderson ctx->iaoq_n = -1; 448651b061fbSRichard Henderson ctx->iaoq_n_var = get_temp(ctx); 4487eaa3783bSRichard Henderson tcg_gen_addi_reg(ctx->iaoq_n_var, cpu_iaoq_b, 4); 448861766fe9SRichard Henderson } else { 448951b061fbSRichard Henderson ctx->iaoq_n = ctx->iaoq_b + 4; 4490f764718dSRichard Henderson ctx->iaoq_n_var = NULL; 449161766fe9SRichard Henderson } 449261766fe9SRichard Henderson 449351b061fbSRichard Henderson if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { 449451b061fbSRichard Henderson ctx->null_cond.c = TCG_COND_NEVER; 4495869051eaSRichard Henderson ret = DISAS_NEXT; 4496129e9cc3SRichard Henderson } else { 44971a19da0dSRichard Henderson ctx->insn = insn; 449831234768SRichard Henderson translate_one(ctx, insn); 449931234768SRichard Henderson ret = ctx->base.is_jmp; 450051b061fbSRichard Henderson assert(ctx->null_lab == NULL); 4501129e9cc3SRichard Henderson } 450261766fe9SRichard Henderson } 450361766fe9SRichard Henderson 450451b061fbSRichard Henderson /* Free any temporaries allocated. */ 450586f8d05fSRichard Henderson for (i = 0, n = ctx->ntempr; i < n; ++i) { 450686f8d05fSRichard Henderson tcg_temp_free(ctx->tempr[i]); 450786f8d05fSRichard Henderson ctx->tempr[i] = NULL; 450861766fe9SRichard Henderson } 450986f8d05fSRichard Henderson for (i = 0, n = ctx->ntempl; i < n; ++i) { 451086f8d05fSRichard Henderson tcg_temp_free_tl(ctx->templ[i]); 451186f8d05fSRichard Henderson ctx->templ[i] = NULL; 451286f8d05fSRichard Henderson } 451386f8d05fSRichard Henderson ctx->ntempr = 0; 451486f8d05fSRichard Henderson ctx->ntempl = 0; 451561766fe9SRichard Henderson 45163d68ee7bSRichard Henderson /* Advance the insn queue. Note that this check also detects 45173d68ee7bSRichard Henderson a priority change within the instruction queue. */ 451851b061fbSRichard Henderson if (ret == DISAS_NEXT && ctx->iaoq_b != ctx->iaoq_f + 4) { 4519c301f34eSRichard Henderson if (ctx->iaoq_b != -1 && ctx->iaoq_n != -1 4520c301f34eSRichard Henderson && use_goto_tb(ctx, ctx->iaoq_b) 4521c301f34eSRichard Henderson && (ctx->null_cond.c == TCG_COND_NEVER 4522c301f34eSRichard Henderson || ctx->null_cond.c == TCG_COND_ALWAYS)) { 452351b061fbSRichard Henderson nullify_set(ctx, ctx->null_cond.c == TCG_COND_ALWAYS); 452451b061fbSRichard Henderson gen_goto_tb(ctx, 0, ctx->iaoq_b, ctx->iaoq_n); 452531234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_NORETURN; 4526129e9cc3SRichard Henderson } else { 452731234768SRichard Henderson ctx->base.is_jmp = ret = DISAS_IAQ_N_STALE; 452861766fe9SRichard Henderson } 4529129e9cc3SRichard Henderson } 453051b061fbSRichard Henderson ctx->iaoq_f = ctx->iaoq_b; 453151b061fbSRichard Henderson ctx->iaoq_b = ctx->iaoq_n; 4532c301f34eSRichard Henderson ctx->base.pc_next += 4; 453361766fe9SRichard Henderson 4534869051eaSRichard Henderson if (ret == DISAS_NORETURN || ret == DISAS_IAQ_N_UPDATED) { 453551b061fbSRichard Henderson return; 453661766fe9SRichard Henderson } 453751b061fbSRichard Henderson if (ctx->iaoq_f == -1) { 4538eaa3783bSRichard Henderson tcg_gen_mov_reg(cpu_iaoq_f, cpu_iaoq_b); 453951b061fbSRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_n, ctx->iaoq_n_var); 4540c301f34eSRichard Henderson #ifndef CONFIG_USER_ONLY 4541c301f34eSRichard Henderson tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b); 4542c301f34eSRichard Henderson #endif 454351b061fbSRichard Henderson nullify_save(ctx); 454451b061fbSRichard Henderson ctx->base.is_jmp = DISAS_IAQ_N_UPDATED; 454551b061fbSRichard Henderson } else if (ctx->iaoq_b == -1) { 4546eaa3783bSRichard Henderson tcg_gen_mov_reg(cpu_iaoq_b, ctx->iaoq_n_var); 454761766fe9SRichard Henderson } 454861766fe9SRichard Henderson } 454961766fe9SRichard Henderson 455051b061fbSRichard Henderson static void hppa_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 455151b061fbSRichard Henderson { 455251b061fbSRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 4553e1b5a5edSRichard Henderson DisasJumpType is_jmp = ctx->base.is_jmp; 455451b061fbSRichard Henderson 4555e1b5a5edSRichard Henderson switch (is_jmp) { 4556869051eaSRichard Henderson case DISAS_NORETURN: 455761766fe9SRichard Henderson break; 455851b061fbSRichard Henderson case DISAS_TOO_MANY: 4559869051eaSRichard Henderson case DISAS_IAQ_N_STALE: 4560e1b5a5edSRichard Henderson case DISAS_IAQ_N_STALE_EXIT: 456151b061fbSRichard Henderson copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f); 456251b061fbSRichard Henderson copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b); 456351b061fbSRichard Henderson nullify_save(ctx); 456461766fe9SRichard Henderson /* FALLTHRU */ 4565869051eaSRichard Henderson case DISAS_IAQ_N_UPDATED: 456651b061fbSRichard Henderson if (ctx->base.singlestep_enabled) { 456761766fe9SRichard Henderson gen_excp_1(EXCP_DEBUG); 4568e1b5a5edSRichard Henderson } else if (is_jmp == DISAS_IAQ_N_STALE_EXIT) { 456907ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 457061766fe9SRichard Henderson } else { 45717f11636dSEmilio G. Cota tcg_gen_lookup_and_goto_ptr(); 457261766fe9SRichard Henderson } 457361766fe9SRichard Henderson break; 457461766fe9SRichard Henderson default: 457551b061fbSRichard Henderson g_assert_not_reached(); 457661766fe9SRichard Henderson } 457751b061fbSRichard Henderson } 457861766fe9SRichard Henderson 457951b061fbSRichard Henderson static void hppa_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) 458051b061fbSRichard Henderson { 4581c301f34eSRichard Henderson target_ulong pc = dcbase->pc_first; 458261766fe9SRichard Henderson 4583ba1d0b44SRichard Henderson #ifdef CONFIG_USER_ONLY 4584ba1d0b44SRichard Henderson switch (pc) { 45857ad439dfSRichard Henderson case 0x00: 458651b061fbSRichard Henderson qemu_log("IN:\n0x00000000: (null)\n"); 4587ba1d0b44SRichard Henderson return; 45887ad439dfSRichard Henderson case 0xb0: 458951b061fbSRichard Henderson qemu_log("IN:\n0x000000b0: light-weight-syscall\n"); 4590ba1d0b44SRichard Henderson return; 45917ad439dfSRichard Henderson case 0xe0: 459251b061fbSRichard Henderson qemu_log("IN:\n0x000000e0: set-thread-pointer-syscall\n"); 4593ba1d0b44SRichard Henderson return; 45947ad439dfSRichard Henderson case 0x100: 459551b061fbSRichard Henderson qemu_log("IN:\n0x00000100: syscall\n"); 4596ba1d0b44SRichard Henderson return; 45977ad439dfSRichard Henderson } 4598ba1d0b44SRichard Henderson #endif 4599ba1d0b44SRichard Henderson 4600ba1d0b44SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(pc)); 4601eaa3783bSRichard Henderson log_target_disas(cs, pc, dcbase->tb->size); 460261766fe9SRichard Henderson } 460351b061fbSRichard Henderson 460451b061fbSRichard Henderson static const TranslatorOps hppa_tr_ops = { 460551b061fbSRichard Henderson .init_disas_context = hppa_tr_init_disas_context, 460651b061fbSRichard Henderson .tb_start = hppa_tr_tb_start, 460751b061fbSRichard Henderson .insn_start = hppa_tr_insn_start, 460851b061fbSRichard Henderson .breakpoint_check = hppa_tr_breakpoint_check, 460951b061fbSRichard Henderson .translate_insn = hppa_tr_translate_insn, 461051b061fbSRichard Henderson .tb_stop = hppa_tr_tb_stop, 461151b061fbSRichard Henderson .disas_log = hppa_tr_disas_log, 461251b061fbSRichard Henderson }; 461351b061fbSRichard Henderson 461451b061fbSRichard Henderson void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) 461551b061fbSRichard Henderson 461651b061fbSRichard Henderson { 461751b061fbSRichard Henderson DisasContext ctx; 461851b061fbSRichard Henderson translator_loop(&hppa_tr_ops, &ctx.base, cs, tb); 461961766fe9SRichard Henderson } 462061766fe9SRichard Henderson 462161766fe9SRichard Henderson void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb, 462261766fe9SRichard Henderson target_ulong *data) 462361766fe9SRichard Henderson { 462461766fe9SRichard Henderson env->iaoq_f = data[0]; 462586f8d05fSRichard Henderson if (data[1] != (target_ureg)-1) { 462661766fe9SRichard Henderson env->iaoq_b = data[1]; 462761766fe9SRichard Henderson } 462861766fe9SRichard Henderson /* Since we were executing the instruction at IAOQ_F, and took some 462961766fe9SRichard Henderson sort of action that provoked the cpu_restore_state, we can infer 463061766fe9SRichard Henderson that the instruction was not nullified. */ 463161766fe9SRichard Henderson env->psw_n = 0; 463261766fe9SRichard Henderson } 4633