1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth SPARC translation 3fcf5ef2aSThomas Huth 4fcf5ef2aSThomas Huth Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at> 5fcf5ef2aSThomas Huth Copyright (C) 2003-2005 Fabrice Bellard 6fcf5ef2aSThomas Huth 7fcf5ef2aSThomas Huth This library is free software; you can redistribute it and/or 8fcf5ef2aSThomas Huth modify it under the terms of the GNU Lesser General Public 9fcf5ef2aSThomas Huth License as published by the Free Software Foundation; either 105650b549SChetan Pant version 2.1 of the License, or (at your option) any later version. 11fcf5ef2aSThomas Huth 12fcf5ef2aSThomas Huth This library is distributed in the hope that it will be useful, 13fcf5ef2aSThomas Huth but WITHOUT ANY WARRANTY; without even the implied warranty of 14fcf5ef2aSThomas Huth MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fcf5ef2aSThomas Huth Lesser General Public License for more details. 16fcf5ef2aSThomas Huth 17fcf5ef2aSThomas Huth You should have received a copy of the GNU Lesser General Public 18fcf5ef2aSThomas Huth License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fcf5ef2aSThomas Huth */ 20fcf5ef2aSThomas Huth 21fcf5ef2aSThomas Huth #include "qemu/osdep.h" 22fcf5ef2aSThomas Huth 23fcf5ef2aSThomas Huth #include "cpu.h" 24fcf5ef2aSThomas Huth #include "disas/disas.h" 25fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 26fcf5ef2aSThomas Huth #include "exec/exec-all.h" 27dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 28fafba1bbSRichard Henderson #include "tcg/tcg-op-gvec.h" 29fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 30c5e6ccdfSEmilio G. Cota #include "exec/translator.h" 31fcf5ef2aSThomas Huth #include "exec/log.h" 32fcf5ef2aSThomas Huth #include "asi.h" 33fcf5ef2aSThomas Huth 34d53106c9SRichard Henderson #define HELPER_H "helper.h" 35d53106c9SRichard Henderson #include "exec/helper-info.c.inc" 36d53106c9SRichard Henderson #undef HELPER_H 37fcf5ef2aSThomas Huth 38668bb9b7SRichard Henderson #ifdef TARGET_SPARC64 39668bb9b7SRichard Henderson # define gen_helper_rdpsr(D, E) qemu_build_not_reached() 4086b82fe0SRichard Henderson # define gen_helper_rett(E) qemu_build_not_reached() 410faef01bSRichard Henderson # define gen_helper_power_down(E) qemu_build_not_reached() 4225524734SRichard Henderson # define gen_helper_wrpsr(E, S) qemu_build_not_reached() 43668bb9b7SRichard Henderson #else 440faef01bSRichard Henderson # define gen_helper_clear_softint(E, S) qemu_build_not_reached() 458f75b8a4SRichard Henderson # define gen_helper_done(E) qemu_build_not_reached() 46e8325dc0SRichard Henderson # define gen_helper_flushw(E) qemu_build_not_reached() 47af25071cSRichard Henderson # define gen_helper_rdccr(D, E) qemu_build_not_reached() 485d617bfbSRichard Henderson # define gen_helper_rdcwp(D, E) qemu_build_not_reached() 4925524734SRichard Henderson # define gen_helper_restored(E) qemu_build_not_reached() 508f75b8a4SRichard Henderson # define gen_helper_retry(E) qemu_build_not_reached() 5125524734SRichard Henderson # define gen_helper_saved(E) qemu_build_not_reached() 520faef01bSRichard Henderson # define gen_helper_set_softint(E, S) qemu_build_not_reached() 53af25071cSRichard Henderson # define gen_helper_tick_get_count(D, E, T, C) qemu_build_not_reached() 549422278eSRichard Henderson # define gen_helper_tick_set_count(P, S) qemu_build_not_reached() 55bb97f2f5SRichard Henderson # define gen_helper_tick_set_limit(P, S) qemu_build_not_reached() 560faef01bSRichard Henderson # define gen_helper_wrccr(E, S) qemu_build_not_reached() 579422278eSRichard Henderson # define gen_helper_wrcwp(E, S) qemu_build_not_reached() 589422278eSRichard Henderson # define gen_helper_wrgl(E, S) qemu_build_not_reached() 590faef01bSRichard Henderson # define gen_helper_write_softint(E, S) qemu_build_not_reached() 609422278eSRichard Henderson # define gen_helper_wrpil(E, S) qemu_build_not_reached() 619422278eSRichard Henderson # define gen_helper_wrpstate(E, S) qemu_build_not_reached() 62e2fa6bd1SRichard Henderson # define gen_helper_fcmpeq16 ({ qemu_build_not_reached(); NULL; }) 63e2fa6bd1SRichard Henderson # define gen_helper_fcmpeq32 ({ qemu_build_not_reached(); NULL; }) 64e2fa6bd1SRichard Henderson # define gen_helper_fcmpgt16 ({ qemu_build_not_reached(); NULL; }) 65e2fa6bd1SRichard Henderson # define gen_helper_fcmpgt32 ({ qemu_build_not_reached(); NULL; }) 66e2fa6bd1SRichard Henderson # define gen_helper_fcmple16 ({ qemu_build_not_reached(); NULL; }) 67e2fa6bd1SRichard Henderson # define gen_helper_fcmple32 ({ qemu_build_not_reached(); NULL; }) 68e2fa6bd1SRichard Henderson # define gen_helper_fcmpne16 ({ qemu_build_not_reached(); NULL; }) 69e2fa6bd1SRichard Henderson # define gen_helper_fcmpne32 ({ qemu_build_not_reached(); NULL; }) 708aa418b3SRichard Henderson # define gen_helper_fdtox ({ qemu_build_not_reached(); NULL; }) 71e06c9f83SRichard Henderson # define gen_helper_fexpand ({ qemu_build_not_reached(); NULL; }) 72e06c9f83SRichard Henderson # define gen_helper_fmul8sux16 ({ qemu_build_not_reached(); NULL; }) 73e06c9f83SRichard Henderson # define gen_helper_fmul8ulx16 ({ qemu_build_not_reached(); NULL; }) 74e06c9f83SRichard Henderson # define gen_helper_fmul8x16al ({ qemu_build_not_reached(); NULL; }) 75e06c9f83SRichard Henderson # define gen_helper_fmul8x16au ({ qemu_build_not_reached(); NULL; }) 76e06c9f83SRichard Henderson # define gen_helper_fmul8x16 ({ qemu_build_not_reached(); NULL; }) 77e06c9f83SRichard Henderson # define gen_helper_fmuld8sux16 ({ qemu_build_not_reached(); NULL; }) 78e06c9f83SRichard Henderson # define gen_helper_fmuld8ulx16 ({ qemu_build_not_reached(); NULL; }) 79e06c9f83SRichard Henderson # define gen_helper_fpmerge ({ qemu_build_not_reached(); NULL; }) 801617586fSRichard Henderson # define gen_helper_fqtox ({ qemu_build_not_reached(); NULL; }) 81199d43efSRichard Henderson # define gen_helper_fstox ({ qemu_build_not_reached(); NULL; }) 828aa418b3SRichard Henderson # define gen_helper_fxtod ({ qemu_build_not_reached(); NULL; }) 837b8e3e1aSRichard Henderson # define gen_helper_fxtoq ({ qemu_build_not_reached(); NULL; }) 84f4e18df5SRichard Henderson # define gen_helper_fxtos ({ qemu_build_not_reached(); NULL; }) 85afb04344SRichard Henderson # define gen_helper_pdist ({ qemu_build_not_reached(); NULL; }) 86668bb9b7SRichard Henderson # define MAXTL_MASK 0 87af25071cSRichard Henderson #endif 88af25071cSRichard Henderson 89633c4283SRichard Henderson /* Dynamic PC, must exit to main loop. */ 90633c4283SRichard Henderson #define DYNAMIC_PC 1 91633c4283SRichard Henderson /* Dynamic PC, one of two values according to jump_pc[T2]. */ 92633c4283SRichard Henderson #define JUMP_PC 2 93633c4283SRichard Henderson /* Dynamic PC, may lookup next TB. */ 94633c4283SRichard Henderson #define DYNAMIC_PC_LOOKUP 3 95fcf5ef2aSThomas Huth 9646bb0137SMark Cave-Ayland #define DISAS_EXIT DISAS_TARGET_0 9746bb0137SMark Cave-Ayland 98fcf5ef2aSThomas Huth /* global register indexes */ 99fcf5ef2aSThomas Huth static TCGv_ptr cpu_regwptr; 100c9fa8e58SRichard Henderson static TCGv cpu_pc, cpu_npc; 101fcf5ef2aSThomas Huth static TCGv cpu_regs[32]; 102fcf5ef2aSThomas Huth static TCGv cpu_y; 103fcf5ef2aSThomas Huth static TCGv cpu_tbr; 104fcf5ef2aSThomas Huth static TCGv cpu_cond; 1052a1905c7SRichard Henderson static TCGv cpu_cc_N; 1062a1905c7SRichard Henderson static TCGv cpu_cc_V; 1072a1905c7SRichard Henderson static TCGv cpu_icc_Z; 1082a1905c7SRichard Henderson static TCGv cpu_icc_C; 109fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 1102a1905c7SRichard Henderson static TCGv cpu_xcc_Z; 1112a1905c7SRichard Henderson static TCGv cpu_xcc_C; 1122a1905c7SRichard Henderson static TCGv_i32 cpu_fprs; 113fcf5ef2aSThomas Huth static TCGv cpu_gsr; 114fcf5ef2aSThomas Huth #else 115af25071cSRichard Henderson # define cpu_fprs ({ qemu_build_not_reached(); (TCGv)NULL; }) 116af25071cSRichard Henderson # define cpu_gsr ({ qemu_build_not_reached(); (TCGv)NULL; }) 117fcf5ef2aSThomas Huth #endif 1182a1905c7SRichard Henderson 1192a1905c7SRichard Henderson #ifdef TARGET_SPARC64 1202a1905c7SRichard Henderson #define cpu_cc_Z cpu_xcc_Z 1212a1905c7SRichard Henderson #define cpu_cc_C cpu_xcc_C 1222a1905c7SRichard Henderson #else 1232a1905c7SRichard Henderson #define cpu_cc_Z cpu_icc_Z 1242a1905c7SRichard Henderson #define cpu_cc_C cpu_icc_C 1252a1905c7SRichard Henderson #define cpu_xcc_Z ({ qemu_build_not_reached(); NULL; }) 1262a1905c7SRichard Henderson #define cpu_xcc_C ({ qemu_build_not_reached(); NULL; }) 1272a1905c7SRichard Henderson #endif 1282a1905c7SRichard Henderson 129fcf5ef2aSThomas Huth /* Floating point registers */ 130fcf5ef2aSThomas Huth static TCGv_i64 cpu_fpr[TARGET_DPREGS]; 131d8c5b92fSRichard Henderson static TCGv_i32 cpu_fcc[TARGET_FCCREGS]; 132fcf5ef2aSThomas Huth 133af25071cSRichard Henderson #define env_field_offsetof(X) offsetof(CPUSPARCState, X) 134af25071cSRichard Henderson #ifdef TARGET_SPARC64 135cd6269f7SRichard Henderson # define env32_field_offsetof(X) ({ qemu_build_not_reached(); 0; }) 136af25071cSRichard Henderson # define env64_field_offsetof(X) env_field_offsetof(X) 137af25071cSRichard Henderson #else 138cd6269f7SRichard Henderson # define env32_field_offsetof(X) env_field_offsetof(X) 139af25071cSRichard Henderson # define env64_field_offsetof(X) ({ qemu_build_not_reached(); 0; }) 140af25071cSRichard Henderson #endif 141af25071cSRichard Henderson 142533f042fSRichard Henderson typedef struct DisasCompare { 143533f042fSRichard Henderson TCGCond cond; 144533f042fSRichard Henderson TCGv c1; 145533f042fSRichard Henderson int c2; 146533f042fSRichard Henderson } DisasCompare; 147533f042fSRichard Henderson 148186e7890SRichard Henderson typedef struct DisasDelayException { 149186e7890SRichard Henderson struct DisasDelayException *next; 150186e7890SRichard Henderson TCGLabel *lab; 151186e7890SRichard Henderson TCGv_i32 excp; 152186e7890SRichard Henderson /* Saved state at parent insn. */ 153186e7890SRichard Henderson target_ulong pc; 154186e7890SRichard Henderson target_ulong npc; 155186e7890SRichard Henderson } DisasDelayException; 156186e7890SRichard Henderson 157fcf5ef2aSThomas Huth typedef struct DisasContext { 158af00be49SEmilio G. Cota DisasContextBase base; 159fcf5ef2aSThomas Huth target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */ 160fcf5ef2aSThomas Huth target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */ 161533f042fSRichard Henderson 162533f042fSRichard Henderson /* Used when JUMP_PC value is used. */ 163533f042fSRichard Henderson DisasCompare jump; 164533f042fSRichard Henderson target_ulong jump_pc[2]; 165533f042fSRichard Henderson 166fcf5ef2aSThomas Huth int mem_idx; 16789527e3aSRichard Henderson bool cpu_cond_live; 168c9b459aaSArtyom Tarasenko bool fpu_enabled; 169c9b459aaSArtyom Tarasenko bool address_mask_32bit; 170c9b459aaSArtyom Tarasenko #ifndef CONFIG_USER_ONLY 171c9b459aaSArtyom Tarasenko bool supervisor; 172c9b459aaSArtyom Tarasenko #ifdef TARGET_SPARC64 173c9b459aaSArtyom Tarasenko bool hypervisor; 174c9b459aaSArtyom Tarasenko #endif 175c9b459aaSArtyom Tarasenko #endif 176c9b459aaSArtyom Tarasenko 177fcf5ef2aSThomas Huth sparc_def_t *def; 178fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 179fcf5ef2aSThomas Huth int fprs_dirty; 180fcf5ef2aSThomas Huth int asi; 181fcf5ef2aSThomas Huth #endif 182186e7890SRichard Henderson DisasDelayException *delay_excp_list; 183fcf5ef2aSThomas Huth } DisasContext; 184fcf5ef2aSThomas Huth 185fcf5ef2aSThomas Huth // This function uses non-native bit order 186fcf5ef2aSThomas Huth #define GET_FIELD(X, FROM, TO) \ 187fcf5ef2aSThomas Huth ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) 188fcf5ef2aSThomas Huth 189fcf5ef2aSThomas Huth // This function uses the order in the manuals, i.e. bit 0 is 2^0 190fcf5ef2aSThomas Huth #define GET_FIELD_SP(X, FROM, TO) \ 191fcf5ef2aSThomas Huth GET_FIELD(X, 31 - (TO), 31 - (FROM)) 192fcf5ef2aSThomas Huth 193fcf5ef2aSThomas Huth #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1) 194fcf5ef2aSThomas Huth #define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1)) 195fcf5ef2aSThomas Huth 196fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 197fcf5ef2aSThomas Huth #define DFPREG(r) (((r & 1) << 5) | (r & 0x1e)) 198fcf5ef2aSThomas Huth #define QFPREG(r) (((r & 1) << 5) | (r & 0x1c)) 199fcf5ef2aSThomas Huth #else 200fcf5ef2aSThomas Huth #define DFPREG(r) (r & 0x1e) 201fcf5ef2aSThomas Huth #define QFPREG(r) (r & 0x1c) 202fcf5ef2aSThomas Huth #endif 203fcf5ef2aSThomas Huth 204fcf5ef2aSThomas Huth #define UA2005_HTRAP_MASK 0xff 205fcf5ef2aSThomas Huth #define V8_TRAP_MASK 0x7f 206fcf5ef2aSThomas Huth 207fcf5ef2aSThomas Huth #define IS_IMM (insn & (1<<13)) 208fcf5ef2aSThomas Huth 2090c2e96c1SRichard Henderson static void gen_update_fprs_dirty(DisasContext *dc, int rd) 210fcf5ef2aSThomas Huth { 211fcf5ef2aSThomas Huth #if defined(TARGET_SPARC64) 212fcf5ef2aSThomas Huth int bit = (rd < 32) ? 1 : 2; 213fcf5ef2aSThomas Huth /* If we know we've already set this bit within the TB, 214fcf5ef2aSThomas Huth we can avoid setting it again. */ 215fcf5ef2aSThomas Huth if (!(dc->fprs_dirty & bit)) { 216fcf5ef2aSThomas Huth dc->fprs_dirty |= bit; 217fcf5ef2aSThomas Huth tcg_gen_ori_i32(cpu_fprs, cpu_fprs, bit); 218fcf5ef2aSThomas Huth } 219fcf5ef2aSThomas Huth #endif 220fcf5ef2aSThomas Huth } 221fcf5ef2aSThomas Huth 222fcf5ef2aSThomas Huth /* floating point registers moves */ 223fcf5ef2aSThomas Huth static TCGv_i32 gen_load_fpr_F(DisasContext *dc, unsigned int src) 224fcf5ef2aSThomas Huth { 22536ab4623SRichard Henderson TCGv_i32 ret = tcg_temp_new_i32(); 226dc41aa7dSRichard Henderson if (src & 1) { 227dc41aa7dSRichard Henderson tcg_gen_extrl_i64_i32(ret, cpu_fpr[src / 2]); 228dc41aa7dSRichard Henderson } else { 229dc41aa7dSRichard Henderson tcg_gen_extrh_i64_i32(ret, cpu_fpr[src / 2]); 230fcf5ef2aSThomas Huth } 231dc41aa7dSRichard Henderson return ret; 232fcf5ef2aSThomas Huth } 233fcf5ef2aSThomas Huth 234fcf5ef2aSThomas Huth static void gen_store_fpr_F(DisasContext *dc, unsigned int dst, TCGv_i32 v) 235fcf5ef2aSThomas Huth { 2368e7bbc75SRichard Henderson TCGv_i64 t = tcg_temp_new_i64(); 2378e7bbc75SRichard Henderson 2388e7bbc75SRichard Henderson tcg_gen_extu_i32_i64(t, v); 239fcf5ef2aSThomas Huth tcg_gen_deposit_i64(cpu_fpr[dst / 2], cpu_fpr[dst / 2], t, 240fcf5ef2aSThomas Huth (dst & 1 ? 0 : 32), 32); 241fcf5ef2aSThomas Huth gen_update_fprs_dirty(dc, dst); 242fcf5ef2aSThomas Huth } 243fcf5ef2aSThomas Huth 244fcf5ef2aSThomas Huth static TCGv_i64 gen_load_fpr_D(DisasContext *dc, unsigned int src) 245fcf5ef2aSThomas Huth { 246fcf5ef2aSThomas Huth src = DFPREG(src); 247fcf5ef2aSThomas Huth return cpu_fpr[src / 2]; 248fcf5ef2aSThomas Huth } 249fcf5ef2aSThomas Huth 250fcf5ef2aSThomas Huth static void gen_store_fpr_D(DisasContext *dc, unsigned int dst, TCGv_i64 v) 251fcf5ef2aSThomas Huth { 252fcf5ef2aSThomas Huth dst = DFPREG(dst); 253fcf5ef2aSThomas Huth tcg_gen_mov_i64(cpu_fpr[dst / 2], v); 254fcf5ef2aSThomas Huth gen_update_fprs_dirty(dc, dst); 255fcf5ef2aSThomas Huth } 256fcf5ef2aSThomas Huth 257fcf5ef2aSThomas Huth static TCGv_i64 gen_dest_fpr_D(DisasContext *dc, unsigned int dst) 258fcf5ef2aSThomas Huth { 259fcf5ef2aSThomas Huth return cpu_fpr[DFPREG(dst) / 2]; 260fcf5ef2aSThomas Huth } 261fcf5ef2aSThomas Huth 26233ec4245SRichard Henderson static TCGv_i128 gen_load_fpr_Q(DisasContext *dc, unsigned int src) 26333ec4245SRichard Henderson { 26433ec4245SRichard Henderson TCGv_i128 ret = tcg_temp_new_i128(); 26533ec4245SRichard Henderson 26633ec4245SRichard Henderson src = QFPREG(src); 26733ec4245SRichard Henderson tcg_gen_concat_i64_i128(ret, cpu_fpr[src / 2 + 1], cpu_fpr[src / 2]); 26833ec4245SRichard Henderson return ret; 26933ec4245SRichard Henderson } 27033ec4245SRichard Henderson 27133ec4245SRichard Henderson static void gen_store_fpr_Q(DisasContext *dc, unsigned int dst, TCGv_i128 v) 27233ec4245SRichard Henderson { 27333ec4245SRichard Henderson dst = DFPREG(dst); 27433ec4245SRichard Henderson tcg_gen_extr_i128_i64(cpu_fpr[dst / 2 + 1], cpu_fpr[dst / 2], v); 27533ec4245SRichard Henderson gen_update_fprs_dirty(dc, dst); 27633ec4245SRichard Henderson } 27733ec4245SRichard Henderson 278fcf5ef2aSThomas Huth /* moves */ 279fcf5ef2aSThomas Huth #ifdef CONFIG_USER_ONLY 280fcf5ef2aSThomas Huth #define supervisor(dc) 0 281fcf5ef2aSThomas Huth #define hypervisor(dc) 0 282fcf5ef2aSThomas Huth #else 283fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 284c9b459aaSArtyom Tarasenko #define hypervisor(dc) (dc->hypervisor) 285c9b459aaSArtyom Tarasenko #define supervisor(dc) (dc->supervisor | dc->hypervisor) 286fcf5ef2aSThomas Huth #else 287c9b459aaSArtyom Tarasenko #define supervisor(dc) (dc->supervisor) 288668bb9b7SRichard Henderson #define hypervisor(dc) 0 289fcf5ef2aSThomas Huth #endif 290fcf5ef2aSThomas Huth #endif 291fcf5ef2aSThomas Huth 292b1bc09eaSRichard Henderson #if !defined(TARGET_SPARC64) 293b1bc09eaSRichard Henderson # define AM_CHECK(dc) false 294b1bc09eaSRichard Henderson #elif defined(TARGET_ABI32) 295b1bc09eaSRichard Henderson # define AM_CHECK(dc) true 296b1bc09eaSRichard Henderson #elif defined(CONFIG_USER_ONLY) 297b1bc09eaSRichard Henderson # define AM_CHECK(dc) false 298fcf5ef2aSThomas Huth #else 299b1bc09eaSRichard Henderson # define AM_CHECK(dc) ((dc)->address_mask_32bit) 300fcf5ef2aSThomas Huth #endif 301fcf5ef2aSThomas Huth 3020c2e96c1SRichard Henderson static void gen_address_mask(DisasContext *dc, TCGv addr) 303fcf5ef2aSThomas Huth { 304b1bc09eaSRichard Henderson if (AM_CHECK(dc)) { 305fcf5ef2aSThomas Huth tcg_gen_andi_tl(addr, addr, 0xffffffffULL); 306b1bc09eaSRichard Henderson } 307fcf5ef2aSThomas Huth } 308fcf5ef2aSThomas Huth 30923ada1b1SRichard Henderson static target_ulong address_mask_i(DisasContext *dc, target_ulong addr) 31023ada1b1SRichard Henderson { 31123ada1b1SRichard Henderson return AM_CHECK(dc) ? (uint32_t)addr : addr; 31223ada1b1SRichard Henderson } 31323ada1b1SRichard Henderson 3140c2e96c1SRichard Henderson static TCGv gen_load_gpr(DisasContext *dc, int reg) 315fcf5ef2aSThomas Huth { 316fcf5ef2aSThomas Huth if (reg > 0) { 317fcf5ef2aSThomas Huth assert(reg < 32); 318fcf5ef2aSThomas Huth return cpu_regs[reg]; 319fcf5ef2aSThomas Huth } else { 32052123f14SRichard Henderson TCGv t = tcg_temp_new(); 321fcf5ef2aSThomas Huth tcg_gen_movi_tl(t, 0); 322fcf5ef2aSThomas Huth return t; 323fcf5ef2aSThomas Huth } 324fcf5ef2aSThomas Huth } 325fcf5ef2aSThomas Huth 3260c2e96c1SRichard Henderson static void gen_store_gpr(DisasContext *dc, int reg, TCGv v) 327fcf5ef2aSThomas Huth { 328fcf5ef2aSThomas Huth if (reg > 0) { 329fcf5ef2aSThomas Huth assert(reg < 32); 330fcf5ef2aSThomas Huth tcg_gen_mov_tl(cpu_regs[reg], v); 331fcf5ef2aSThomas Huth } 332fcf5ef2aSThomas Huth } 333fcf5ef2aSThomas Huth 3340c2e96c1SRichard Henderson static TCGv gen_dest_gpr(DisasContext *dc, int reg) 335fcf5ef2aSThomas Huth { 336fcf5ef2aSThomas Huth if (reg > 0) { 337fcf5ef2aSThomas Huth assert(reg < 32); 338fcf5ef2aSThomas Huth return cpu_regs[reg]; 339fcf5ef2aSThomas Huth } else { 34052123f14SRichard Henderson return tcg_temp_new(); 341fcf5ef2aSThomas Huth } 342fcf5ef2aSThomas Huth } 343fcf5ef2aSThomas Huth 3445645aa2eSRichard Henderson static bool use_goto_tb(DisasContext *s, target_ulong pc, target_ulong npc) 345fcf5ef2aSThomas Huth { 3465645aa2eSRichard Henderson return translator_use_goto_tb(&s->base, pc) && 3475645aa2eSRichard Henderson translator_use_goto_tb(&s->base, npc); 348fcf5ef2aSThomas Huth } 349fcf5ef2aSThomas Huth 3505645aa2eSRichard Henderson static void gen_goto_tb(DisasContext *s, int tb_num, 351fcf5ef2aSThomas Huth target_ulong pc, target_ulong npc) 352fcf5ef2aSThomas Huth { 353fcf5ef2aSThomas Huth if (use_goto_tb(s, pc, npc)) { 354fcf5ef2aSThomas Huth /* jump to same page: we can use a direct jump */ 355fcf5ef2aSThomas Huth tcg_gen_goto_tb(tb_num); 356fcf5ef2aSThomas Huth tcg_gen_movi_tl(cpu_pc, pc); 357fcf5ef2aSThomas Huth tcg_gen_movi_tl(cpu_npc, npc); 35807ea28b4SRichard Henderson tcg_gen_exit_tb(s->base.tb, tb_num); 359fcf5ef2aSThomas Huth } else { 360f67ccb2fSRichard Henderson /* jump to another page: we can use an indirect jump */ 361fcf5ef2aSThomas Huth tcg_gen_movi_tl(cpu_pc, pc); 362fcf5ef2aSThomas Huth tcg_gen_movi_tl(cpu_npc, npc); 363f67ccb2fSRichard Henderson tcg_gen_lookup_and_goto_ptr(); 364fcf5ef2aSThomas Huth } 365fcf5ef2aSThomas Huth } 366fcf5ef2aSThomas Huth 367b989ce73SRichard Henderson static TCGv gen_carry32(void) 368fcf5ef2aSThomas Huth { 369b989ce73SRichard Henderson if (TARGET_LONG_BITS == 64) { 370b989ce73SRichard Henderson TCGv t = tcg_temp_new(); 371b989ce73SRichard Henderson tcg_gen_extract_tl(t, cpu_icc_C, 32, 1); 372b989ce73SRichard Henderson return t; 373b989ce73SRichard Henderson } 374b989ce73SRichard Henderson return cpu_icc_C; 375fcf5ef2aSThomas Huth } 376fcf5ef2aSThomas Huth 377b989ce73SRichard Henderson static void gen_op_addcc_int(TCGv dst, TCGv src1, TCGv src2, TCGv cin) 378fcf5ef2aSThomas Huth { 379b989ce73SRichard Henderson TCGv z = tcg_constant_tl(0); 380fcf5ef2aSThomas Huth 381b989ce73SRichard Henderson if (cin) { 382b989ce73SRichard Henderson tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, src1, z, cin, z); 383b989ce73SRichard Henderson tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, cpu_cc_N, cpu_cc_C, src2, z); 384b989ce73SRichard Henderson } else { 385b989ce73SRichard Henderson tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, src1, z, src2, z); 386b989ce73SRichard Henderson } 387b989ce73SRichard Henderson tcg_gen_xor_tl(cpu_cc_Z, src1, src2); 388b989ce73SRichard Henderson tcg_gen_xor_tl(cpu_cc_V, cpu_cc_N, src2); 389b989ce73SRichard Henderson tcg_gen_andc_tl(cpu_cc_V, cpu_cc_V, cpu_cc_Z); 390b989ce73SRichard Henderson if (TARGET_LONG_BITS == 64) { 391b989ce73SRichard Henderson /* 392b989ce73SRichard Henderson * Carry-in to bit 32 is result ^ src1 ^ src2. 393b989ce73SRichard Henderson * We already have the src xor term in Z, from computation of V. 394b989ce73SRichard Henderson */ 395b989ce73SRichard Henderson tcg_gen_xor_tl(cpu_icc_C, cpu_cc_Z, cpu_cc_N); 396b989ce73SRichard Henderson tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N); 397b989ce73SRichard Henderson } 398b989ce73SRichard Henderson tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N); 399b989ce73SRichard Henderson tcg_gen_mov_tl(dst, cpu_cc_N); 400b989ce73SRichard Henderson } 401fcf5ef2aSThomas Huth 402b989ce73SRichard Henderson static void gen_op_addcc(TCGv dst, TCGv src1, TCGv src2) 403b989ce73SRichard Henderson { 404b989ce73SRichard Henderson gen_op_addcc_int(dst, src1, src2, NULL); 405b989ce73SRichard Henderson } 406fcf5ef2aSThomas Huth 407b989ce73SRichard Henderson static void gen_op_taddcc(TCGv dst, TCGv src1, TCGv src2) 408b989ce73SRichard Henderson { 409b989ce73SRichard Henderson TCGv t = tcg_temp_new(); 410b989ce73SRichard Henderson 411b989ce73SRichard Henderson /* Save the tag bits around modification of dst. */ 412b989ce73SRichard Henderson tcg_gen_or_tl(t, src1, src2); 413b989ce73SRichard Henderson 414b989ce73SRichard Henderson gen_op_addcc(dst, src1, src2); 415b989ce73SRichard Henderson 416b989ce73SRichard Henderson /* Incorprate tag bits into icc.V */ 417b989ce73SRichard Henderson tcg_gen_andi_tl(t, t, 3); 418b989ce73SRichard Henderson tcg_gen_neg_tl(t, t); 419b989ce73SRichard Henderson tcg_gen_ext32u_tl(t, t); 420b989ce73SRichard Henderson tcg_gen_or_tl(cpu_cc_V, cpu_cc_V, t); 421b989ce73SRichard Henderson } 422b989ce73SRichard Henderson 423b989ce73SRichard Henderson static void gen_op_addc(TCGv dst, TCGv src1, TCGv src2) 424b989ce73SRichard Henderson { 425b989ce73SRichard Henderson tcg_gen_add_tl(dst, src1, src2); 426b989ce73SRichard Henderson tcg_gen_add_tl(dst, dst, gen_carry32()); 427b989ce73SRichard Henderson } 428b989ce73SRichard Henderson 429b989ce73SRichard Henderson static void gen_op_addccc(TCGv dst, TCGv src1, TCGv src2) 430b989ce73SRichard Henderson { 431b989ce73SRichard Henderson gen_op_addcc_int(dst, src1, src2, gen_carry32()); 432fcf5ef2aSThomas Huth } 433fcf5ef2aSThomas Huth 434f828df74SRichard Henderson static void gen_op_subcc_int(TCGv dst, TCGv src1, TCGv src2, TCGv cin) 435fcf5ef2aSThomas Huth { 436f828df74SRichard Henderson TCGv z = tcg_constant_tl(0); 437fcf5ef2aSThomas Huth 438f828df74SRichard Henderson if (cin) { 439f828df74SRichard Henderson tcg_gen_sub2_tl(cpu_cc_N, cpu_cc_C, src1, z, cin, z); 440f828df74SRichard Henderson tcg_gen_sub2_tl(cpu_cc_N, cpu_cc_C, cpu_cc_N, cpu_cc_C, src2, z); 441f828df74SRichard Henderson } else { 442f828df74SRichard Henderson tcg_gen_sub2_tl(cpu_cc_N, cpu_cc_C, src1, z, src2, z); 443f828df74SRichard Henderson } 444f828df74SRichard Henderson tcg_gen_neg_tl(cpu_cc_C, cpu_cc_C); 445f828df74SRichard Henderson tcg_gen_xor_tl(cpu_cc_Z, src1, src2); 446f828df74SRichard Henderson tcg_gen_xor_tl(cpu_cc_V, cpu_cc_N, src1); 447f828df74SRichard Henderson tcg_gen_and_tl(cpu_cc_V, cpu_cc_V, cpu_cc_Z); 448f828df74SRichard Henderson #ifdef TARGET_SPARC64 449f828df74SRichard Henderson tcg_gen_xor_tl(cpu_icc_C, cpu_cc_Z, cpu_cc_N); 450f828df74SRichard Henderson tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N); 451fcf5ef2aSThomas Huth #endif 452f828df74SRichard Henderson tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N); 453f828df74SRichard Henderson tcg_gen_mov_tl(dst, cpu_cc_N); 454fcf5ef2aSThomas Huth } 455fcf5ef2aSThomas Huth 456f828df74SRichard Henderson static void gen_op_subcc(TCGv dst, TCGv src1, TCGv src2) 457fcf5ef2aSThomas Huth { 458f828df74SRichard Henderson gen_op_subcc_int(dst, src1, src2, NULL); 459fcf5ef2aSThomas Huth } 460fcf5ef2aSThomas Huth 461f828df74SRichard Henderson static void gen_op_tsubcc(TCGv dst, TCGv src1, TCGv src2) 462fcf5ef2aSThomas Huth { 463f828df74SRichard Henderson TCGv t = tcg_temp_new(); 464fcf5ef2aSThomas Huth 465f828df74SRichard Henderson /* Save the tag bits around modification of dst. */ 466f828df74SRichard Henderson tcg_gen_or_tl(t, src1, src2); 467fcf5ef2aSThomas Huth 468f828df74SRichard Henderson gen_op_subcc(dst, src1, src2); 469f828df74SRichard Henderson 470f828df74SRichard Henderson /* Incorprate tag bits into icc.V */ 471f828df74SRichard Henderson tcg_gen_andi_tl(t, t, 3); 472f828df74SRichard Henderson tcg_gen_neg_tl(t, t); 473f828df74SRichard Henderson tcg_gen_ext32u_tl(t, t); 474f828df74SRichard Henderson tcg_gen_or_tl(cpu_cc_V, cpu_cc_V, t); 475f828df74SRichard Henderson } 476f828df74SRichard Henderson 477f828df74SRichard Henderson static void gen_op_subc(TCGv dst, TCGv src1, TCGv src2) 478f828df74SRichard Henderson { 479fcf5ef2aSThomas Huth tcg_gen_sub_tl(dst, src1, src2); 480f828df74SRichard Henderson tcg_gen_sub_tl(dst, dst, gen_carry32()); 481fcf5ef2aSThomas Huth } 482fcf5ef2aSThomas Huth 483f828df74SRichard Henderson static void gen_op_subccc(TCGv dst, TCGv src1, TCGv src2) 484dfebb950SRichard Henderson { 485f828df74SRichard Henderson gen_op_subcc_int(dst, src1, src2, gen_carry32()); 486dfebb950SRichard Henderson } 487dfebb950SRichard Henderson 4880c2e96c1SRichard Henderson static void gen_op_mulscc(TCGv dst, TCGv src1, TCGv src2) 489fcf5ef2aSThomas Huth { 490b989ce73SRichard Henderson TCGv zero = tcg_constant_tl(0); 491*50280618SRichard Henderson TCGv one = tcg_constant_tl(1); 492b989ce73SRichard Henderson TCGv t_src1 = tcg_temp_new(); 493b989ce73SRichard Henderson TCGv t_src2 = tcg_temp_new(); 494b989ce73SRichard Henderson TCGv t0 = tcg_temp_new(); 495fcf5ef2aSThomas Huth 496b989ce73SRichard Henderson tcg_gen_ext32u_tl(t_src1, src1); 497b989ce73SRichard Henderson tcg_gen_ext32u_tl(t_src2, src2); 498fcf5ef2aSThomas Huth 499b989ce73SRichard Henderson /* 500b989ce73SRichard Henderson * if (!(env->y & 1)) 501b989ce73SRichard Henderson * src2 = 0; 502fcf5ef2aSThomas Huth */ 503*50280618SRichard Henderson tcg_gen_movcond_tl(TCG_COND_TSTEQ, t_src2, cpu_y, one, zero, t_src2); 504fcf5ef2aSThomas Huth 505b989ce73SRichard Henderson /* 506b989ce73SRichard Henderson * b2 = src1 & 1; 507b989ce73SRichard Henderson * y = (b2 << 31) | (y >> 1); 508b989ce73SRichard Henderson */ 5090b1183e3SPhilippe Mathieu-Daudé tcg_gen_extract_tl(t0, cpu_y, 1, 31); 510b989ce73SRichard Henderson tcg_gen_deposit_tl(cpu_y, t0, src1, 31, 1); 511fcf5ef2aSThomas Huth 512fcf5ef2aSThomas Huth // b1 = N ^ V; 5132a1905c7SRichard Henderson tcg_gen_xor_tl(t0, cpu_cc_N, cpu_cc_V); 514fcf5ef2aSThomas Huth 515b989ce73SRichard Henderson /* 516b989ce73SRichard Henderson * src1 = (b1 << 31) | (src1 >> 1) 517b989ce73SRichard Henderson */ 5182a1905c7SRichard Henderson tcg_gen_andi_tl(t0, t0, 1u << 31); 519b989ce73SRichard Henderson tcg_gen_shri_tl(t_src1, t_src1, 1); 520b989ce73SRichard Henderson tcg_gen_or_tl(t_src1, t_src1, t0); 521fcf5ef2aSThomas Huth 522b989ce73SRichard Henderson gen_op_addcc(dst, t_src1, t_src2); 523fcf5ef2aSThomas Huth } 524fcf5ef2aSThomas Huth 5250c2e96c1SRichard Henderson static void gen_op_multiply(TCGv dst, TCGv src1, TCGv src2, int sign_ext) 526fcf5ef2aSThomas Huth { 527fcf5ef2aSThomas Huth #if TARGET_LONG_BITS == 32 528fcf5ef2aSThomas Huth if (sign_ext) { 529fcf5ef2aSThomas Huth tcg_gen_muls2_tl(dst, cpu_y, src1, src2); 530fcf5ef2aSThomas Huth } else { 531fcf5ef2aSThomas Huth tcg_gen_mulu2_tl(dst, cpu_y, src1, src2); 532fcf5ef2aSThomas Huth } 533fcf5ef2aSThomas Huth #else 534fcf5ef2aSThomas Huth TCGv t0 = tcg_temp_new_i64(); 535fcf5ef2aSThomas Huth TCGv t1 = tcg_temp_new_i64(); 536fcf5ef2aSThomas Huth 537fcf5ef2aSThomas Huth if (sign_ext) { 538fcf5ef2aSThomas Huth tcg_gen_ext32s_i64(t0, src1); 539fcf5ef2aSThomas Huth tcg_gen_ext32s_i64(t1, src2); 540fcf5ef2aSThomas Huth } else { 541fcf5ef2aSThomas Huth tcg_gen_ext32u_i64(t0, src1); 542fcf5ef2aSThomas Huth tcg_gen_ext32u_i64(t1, src2); 543fcf5ef2aSThomas Huth } 544fcf5ef2aSThomas Huth 545fcf5ef2aSThomas Huth tcg_gen_mul_i64(dst, t0, t1); 546fcf5ef2aSThomas Huth tcg_gen_shri_i64(cpu_y, dst, 32); 547fcf5ef2aSThomas Huth #endif 548fcf5ef2aSThomas Huth } 549fcf5ef2aSThomas Huth 5500c2e96c1SRichard Henderson static void gen_op_umul(TCGv dst, TCGv src1, TCGv src2) 551fcf5ef2aSThomas Huth { 552fcf5ef2aSThomas Huth /* zero-extend truncated operands before multiplication */ 553fcf5ef2aSThomas Huth gen_op_multiply(dst, src1, src2, 0); 554fcf5ef2aSThomas Huth } 555fcf5ef2aSThomas Huth 5560c2e96c1SRichard Henderson static void gen_op_smul(TCGv dst, TCGv src1, TCGv src2) 557fcf5ef2aSThomas Huth { 558fcf5ef2aSThomas Huth /* sign-extend truncated operands before multiplication */ 559fcf5ef2aSThomas Huth gen_op_multiply(dst, src1, src2, 1); 560fcf5ef2aSThomas Huth } 561fcf5ef2aSThomas Huth 562c2636853SRichard Henderson static void gen_op_sdiv(TCGv dst, TCGv src1, TCGv src2) 563c2636853SRichard Henderson { 56413260103SRichard Henderson #ifdef TARGET_SPARC64 565c2636853SRichard Henderson gen_helper_sdiv(dst, tcg_env, src1, src2); 56613260103SRichard Henderson tcg_gen_ext32s_tl(dst, dst); 56713260103SRichard Henderson #else 56813260103SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 56913260103SRichard Henderson gen_helper_sdiv(t64, tcg_env, src1, src2); 57013260103SRichard Henderson tcg_gen_trunc_i64_tl(dst, t64); 57113260103SRichard Henderson #endif 572c2636853SRichard Henderson } 573c2636853SRichard Henderson 574c2636853SRichard Henderson static void gen_op_udivcc(TCGv dst, TCGv src1, TCGv src2) 575c2636853SRichard Henderson { 57613260103SRichard Henderson TCGv_i64 t64; 57713260103SRichard Henderson 57813260103SRichard Henderson #ifdef TARGET_SPARC64 57913260103SRichard Henderson t64 = cpu_cc_V; 58013260103SRichard Henderson #else 58113260103SRichard Henderson t64 = tcg_temp_new_i64(); 58213260103SRichard Henderson #endif 58313260103SRichard Henderson 58413260103SRichard Henderson gen_helper_udiv(t64, tcg_env, src1, src2); 58513260103SRichard Henderson 58613260103SRichard Henderson #ifdef TARGET_SPARC64 58713260103SRichard Henderson tcg_gen_ext32u_tl(cpu_cc_N, t64); 58813260103SRichard Henderson tcg_gen_shri_tl(cpu_cc_V, t64, 32); 58913260103SRichard Henderson tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N); 59013260103SRichard Henderson tcg_gen_movi_tl(cpu_icc_C, 0); 59113260103SRichard Henderson #else 59213260103SRichard Henderson tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64); 59313260103SRichard Henderson #endif 59413260103SRichard Henderson tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N); 59513260103SRichard Henderson tcg_gen_movi_tl(cpu_cc_C, 0); 59613260103SRichard Henderson tcg_gen_mov_tl(dst, cpu_cc_N); 597c2636853SRichard Henderson } 598c2636853SRichard Henderson 599c2636853SRichard Henderson static void gen_op_sdivcc(TCGv dst, TCGv src1, TCGv src2) 600c2636853SRichard Henderson { 60113260103SRichard Henderson TCGv_i64 t64; 60213260103SRichard Henderson 60313260103SRichard Henderson #ifdef TARGET_SPARC64 60413260103SRichard Henderson t64 = cpu_cc_V; 60513260103SRichard Henderson #else 60613260103SRichard Henderson t64 = tcg_temp_new_i64(); 60713260103SRichard Henderson #endif 60813260103SRichard Henderson 60913260103SRichard Henderson gen_helper_sdiv(t64, tcg_env, src1, src2); 61013260103SRichard Henderson 61113260103SRichard Henderson #ifdef TARGET_SPARC64 61213260103SRichard Henderson tcg_gen_ext32s_tl(cpu_cc_N, t64); 61313260103SRichard Henderson tcg_gen_shri_tl(cpu_cc_V, t64, 32); 61413260103SRichard Henderson tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N); 61513260103SRichard Henderson tcg_gen_movi_tl(cpu_icc_C, 0); 61613260103SRichard Henderson #else 61713260103SRichard Henderson tcg_gen_extr_i64_tl(cpu_cc_N, cpu_cc_V, t64); 61813260103SRichard Henderson #endif 61913260103SRichard Henderson tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N); 62013260103SRichard Henderson tcg_gen_movi_tl(cpu_cc_C, 0); 62113260103SRichard Henderson tcg_gen_mov_tl(dst, cpu_cc_N); 622c2636853SRichard Henderson } 623c2636853SRichard Henderson 624a9aba13dSRichard Henderson static void gen_op_taddcctv(TCGv dst, TCGv src1, TCGv src2) 625a9aba13dSRichard Henderson { 626a9aba13dSRichard Henderson gen_helper_taddcctv(dst, tcg_env, src1, src2); 627a9aba13dSRichard Henderson } 628a9aba13dSRichard Henderson 629a9aba13dSRichard Henderson static void gen_op_tsubcctv(TCGv dst, TCGv src1, TCGv src2) 630a9aba13dSRichard Henderson { 631a9aba13dSRichard Henderson gen_helper_tsubcctv(dst, tcg_env, src1, src2); 632a9aba13dSRichard Henderson } 633a9aba13dSRichard Henderson 6349c6ec5bcSRichard Henderson static void gen_op_popc(TCGv dst, TCGv src1, TCGv src2) 6359c6ec5bcSRichard Henderson { 6369c6ec5bcSRichard Henderson tcg_gen_ctpop_tl(dst, src2); 6379c6ec5bcSRichard Henderson } 6389c6ec5bcSRichard Henderson 63945bfed3bSRichard Henderson #ifndef TARGET_SPARC64 64045bfed3bSRichard Henderson static void gen_helper_array8(TCGv dst, TCGv src1, TCGv src2) 64145bfed3bSRichard Henderson { 64245bfed3bSRichard Henderson g_assert_not_reached(); 64345bfed3bSRichard Henderson } 64445bfed3bSRichard Henderson #endif 64545bfed3bSRichard Henderson 64645bfed3bSRichard Henderson static void gen_op_array16(TCGv dst, TCGv src1, TCGv src2) 64745bfed3bSRichard Henderson { 64845bfed3bSRichard Henderson gen_helper_array8(dst, src1, src2); 64945bfed3bSRichard Henderson tcg_gen_shli_tl(dst, dst, 1); 65045bfed3bSRichard Henderson } 65145bfed3bSRichard Henderson 65245bfed3bSRichard Henderson static void gen_op_array32(TCGv dst, TCGv src1, TCGv src2) 65345bfed3bSRichard Henderson { 65445bfed3bSRichard Henderson gen_helper_array8(dst, src1, src2); 65545bfed3bSRichard Henderson tcg_gen_shli_tl(dst, dst, 2); 65645bfed3bSRichard Henderson } 65745bfed3bSRichard Henderson 6582f722641SRichard Henderson static void gen_op_fpack16(TCGv_i32 dst, TCGv_i64 src) 6592f722641SRichard Henderson { 6602f722641SRichard Henderson #ifdef TARGET_SPARC64 6612f722641SRichard Henderson gen_helper_fpack16(dst, cpu_gsr, src); 6622f722641SRichard Henderson #else 6632f722641SRichard Henderson g_assert_not_reached(); 6642f722641SRichard Henderson #endif 6652f722641SRichard Henderson } 6662f722641SRichard Henderson 6672f722641SRichard Henderson static void gen_op_fpackfix(TCGv_i32 dst, TCGv_i64 src) 6682f722641SRichard Henderson { 6692f722641SRichard Henderson #ifdef TARGET_SPARC64 6702f722641SRichard Henderson gen_helper_fpackfix(dst, cpu_gsr, src); 6712f722641SRichard Henderson #else 6722f722641SRichard Henderson g_assert_not_reached(); 6732f722641SRichard Henderson #endif 6742f722641SRichard Henderson } 6752f722641SRichard Henderson 6764b6edc0aSRichard Henderson static void gen_op_fpack32(TCGv_i64 dst, TCGv_i64 src1, TCGv_i64 src2) 6774b6edc0aSRichard Henderson { 6784b6edc0aSRichard Henderson #ifdef TARGET_SPARC64 6794b6edc0aSRichard Henderson gen_helper_fpack32(dst, cpu_gsr, src1, src2); 6804b6edc0aSRichard Henderson #else 6814b6edc0aSRichard Henderson g_assert_not_reached(); 6824b6edc0aSRichard Henderson #endif 6834b6edc0aSRichard Henderson } 6844b6edc0aSRichard Henderson 6854b6edc0aSRichard Henderson static void gen_op_faligndata(TCGv_i64 dst, TCGv_i64 s1, TCGv_i64 s2) 6864b6edc0aSRichard Henderson { 6874b6edc0aSRichard Henderson #ifdef TARGET_SPARC64 6884b6edc0aSRichard Henderson TCGv t1, t2, shift; 6894b6edc0aSRichard Henderson 6904b6edc0aSRichard Henderson t1 = tcg_temp_new(); 6914b6edc0aSRichard Henderson t2 = tcg_temp_new(); 6924b6edc0aSRichard Henderson shift = tcg_temp_new(); 6934b6edc0aSRichard Henderson 6944b6edc0aSRichard Henderson tcg_gen_andi_tl(shift, cpu_gsr, 7); 6954b6edc0aSRichard Henderson tcg_gen_shli_tl(shift, shift, 3); 6964b6edc0aSRichard Henderson tcg_gen_shl_tl(t1, s1, shift); 6974b6edc0aSRichard Henderson 6984b6edc0aSRichard Henderson /* 6994b6edc0aSRichard Henderson * A shift of 64 does not produce 0 in TCG. Divide this into a 7004b6edc0aSRichard Henderson * shift of (up to 63) followed by a constant shift of 1. 7014b6edc0aSRichard Henderson */ 7024b6edc0aSRichard Henderson tcg_gen_xori_tl(shift, shift, 63); 7034b6edc0aSRichard Henderson tcg_gen_shr_tl(t2, s2, shift); 7044b6edc0aSRichard Henderson tcg_gen_shri_tl(t2, t2, 1); 7054b6edc0aSRichard Henderson 7064b6edc0aSRichard Henderson tcg_gen_or_tl(dst, t1, t2); 7074b6edc0aSRichard Henderson #else 7084b6edc0aSRichard Henderson g_assert_not_reached(); 7094b6edc0aSRichard Henderson #endif 7104b6edc0aSRichard Henderson } 7114b6edc0aSRichard Henderson 7124b6edc0aSRichard Henderson static void gen_op_bshuffle(TCGv_i64 dst, TCGv_i64 src1, TCGv_i64 src2) 7134b6edc0aSRichard Henderson { 7144b6edc0aSRichard Henderson #ifdef TARGET_SPARC64 7154b6edc0aSRichard Henderson gen_helper_bshuffle(dst, cpu_gsr, src1, src2); 7164b6edc0aSRichard Henderson #else 7174b6edc0aSRichard Henderson g_assert_not_reached(); 7184b6edc0aSRichard Henderson #endif 7194b6edc0aSRichard Henderson } 7204b6edc0aSRichard Henderson 72189527e3aSRichard Henderson static void finishing_insn(DisasContext *dc) 72289527e3aSRichard Henderson { 72389527e3aSRichard Henderson /* 72489527e3aSRichard Henderson * From here, there is no future path through an unwinding exception. 72589527e3aSRichard Henderson * If the current insn cannot raise an exception, the computation of 72689527e3aSRichard Henderson * cpu_cond may be able to be elided. 72789527e3aSRichard Henderson */ 72889527e3aSRichard Henderson if (dc->cpu_cond_live) { 72989527e3aSRichard Henderson tcg_gen_discard_tl(cpu_cond); 73089527e3aSRichard Henderson dc->cpu_cond_live = false; 73189527e3aSRichard Henderson } 73289527e3aSRichard Henderson } 73389527e3aSRichard Henderson 7340c2e96c1SRichard Henderson static void gen_generic_branch(DisasContext *dc) 735fcf5ef2aSThomas Huth { 73600ab7e61SRichard Henderson TCGv npc0 = tcg_constant_tl(dc->jump_pc[0]); 73700ab7e61SRichard Henderson TCGv npc1 = tcg_constant_tl(dc->jump_pc[1]); 738533f042fSRichard Henderson TCGv c2 = tcg_constant_tl(dc->jump.c2); 739fcf5ef2aSThomas Huth 740533f042fSRichard Henderson tcg_gen_movcond_tl(dc->jump.cond, cpu_npc, dc->jump.c1, c2, npc0, npc1); 741fcf5ef2aSThomas Huth } 742fcf5ef2aSThomas Huth 743fcf5ef2aSThomas Huth /* call this function before using the condition register as it may 744fcf5ef2aSThomas Huth have been set for a jump */ 7450c2e96c1SRichard Henderson static void flush_cond(DisasContext *dc) 746fcf5ef2aSThomas Huth { 747fcf5ef2aSThomas Huth if (dc->npc == JUMP_PC) { 748fcf5ef2aSThomas Huth gen_generic_branch(dc); 74999c82c47SRichard Henderson dc->npc = DYNAMIC_PC_LOOKUP; 750fcf5ef2aSThomas Huth } 751fcf5ef2aSThomas Huth } 752fcf5ef2aSThomas Huth 7530c2e96c1SRichard Henderson static void save_npc(DisasContext *dc) 754fcf5ef2aSThomas Huth { 755633c4283SRichard Henderson if (dc->npc & 3) { 756633c4283SRichard Henderson switch (dc->npc) { 757633c4283SRichard Henderson case JUMP_PC: 758fcf5ef2aSThomas Huth gen_generic_branch(dc); 75999c82c47SRichard Henderson dc->npc = DYNAMIC_PC_LOOKUP; 760633c4283SRichard Henderson break; 761633c4283SRichard Henderson case DYNAMIC_PC: 762633c4283SRichard Henderson case DYNAMIC_PC_LOOKUP: 763633c4283SRichard Henderson break; 764633c4283SRichard Henderson default: 765633c4283SRichard Henderson g_assert_not_reached(); 766633c4283SRichard Henderson } 767633c4283SRichard Henderson } else { 768fcf5ef2aSThomas Huth tcg_gen_movi_tl(cpu_npc, dc->npc); 769fcf5ef2aSThomas Huth } 770fcf5ef2aSThomas Huth } 771fcf5ef2aSThomas Huth 7720c2e96c1SRichard Henderson static void save_state(DisasContext *dc) 773fcf5ef2aSThomas Huth { 774fcf5ef2aSThomas Huth tcg_gen_movi_tl(cpu_pc, dc->pc); 775fcf5ef2aSThomas Huth save_npc(dc); 776fcf5ef2aSThomas Huth } 777fcf5ef2aSThomas Huth 778fcf5ef2aSThomas Huth static void gen_exception(DisasContext *dc, int which) 779fcf5ef2aSThomas Huth { 78089527e3aSRichard Henderson finishing_insn(dc); 781fcf5ef2aSThomas Huth save_state(dc); 782ad75a51eSRichard Henderson gen_helper_raise_exception(tcg_env, tcg_constant_i32(which)); 783af00be49SEmilio G. Cota dc->base.is_jmp = DISAS_NORETURN; 784fcf5ef2aSThomas Huth } 785fcf5ef2aSThomas Huth 786186e7890SRichard Henderson static TCGLabel *delay_exceptionv(DisasContext *dc, TCGv_i32 excp) 787fcf5ef2aSThomas Huth { 788186e7890SRichard Henderson DisasDelayException *e = g_new0(DisasDelayException, 1); 789186e7890SRichard Henderson 790186e7890SRichard Henderson e->next = dc->delay_excp_list; 791186e7890SRichard Henderson dc->delay_excp_list = e; 792186e7890SRichard Henderson 793186e7890SRichard Henderson e->lab = gen_new_label(); 794186e7890SRichard Henderson e->excp = excp; 795186e7890SRichard Henderson e->pc = dc->pc; 796186e7890SRichard Henderson /* Caller must have used flush_cond before branch. */ 797186e7890SRichard Henderson assert(e->npc != JUMP_PC); 798186e7890SRichard Henderson e->npc = dc->npc; 799186e7890SRichard Henderson 800186e7890SRichard Henderson return e->lab; 801186e7890SRichard Henderson } 802186e7890SRichard Henderson 803186e7890SRichard Henderson static TCGLabel *delay_exception(DisasContext *dc, int excp) 804186e7890SRichard Henderson { 805186e7890SRichard Henderson return delay_exceptionv(dc, tcg_constant_i32(excp)); 806186e7890SRichard Henderson } 807186e7890SRichard Henderson 808186e7890SRichard Henderson static void gen_check_align(DisasContext *dc, TCGv addr, int mask) 809186e7890SRichard Henderson { 810186e7890SRichard Henderson TCGv t = tcg_temp_new(); 811186e7890SRichard Henderson TCGLabel *lab; 812186e7890SRichard Henderson 813186e7890SRichard Henderson tcg_gen_andi_tl(t, addr, mask); 814186e7890SRichard Henderson 815186e7890SRichard Henderson flush_cond(dc); 816186e7890SRichard Henderson lab = delay_exception(dc, TT_UNALIGNED); 817186e7890SRichard Henderson tcg_gen_brcondi_tl(TCG_COND_NE, t, 0, lab); 818fcf5ef2aSThomas Huth } 819fcf5ef2aSThomas Huth 8200c2e96c1SRichard Henderson static void gen_mov_pc_npc(DisasContext *dc) 821fcf5ef2aSThomas Huth { 82289527e3aSRichard Henderson finishing_insn(dc); 82389527e3aSRichard Henderson 824633c4283SRichard Henderson if (dc->npc & 3) { 825633c4283SRichard Henderson switch (dc->npc) { 826633c4283SRichard Henderson case JUMP_PC: 827fcf5ef2aSThomas Huth gen_generic_branch(dc); 828fcf5ef2aSThomas Huth tcg_gen_mov_tl(cpu_pc, cpu_npc); 82999c82c47SRichard Henderson dc->pc = DYNAMIC_PC_LOOKUP; 830633c4283SRichard Henderson break; 831633c4283SRichard Henderson case DYNAMIC_PC: 832633c4283SRichard Henderson case DYNAMIC_PC_LOOKUP: 833fcf5ef2aSThomas Huth tcg_gen_mov_tl(cpu_pc, cpu_npc); 834633c4283SRichard Henderson dc->pc = dc->npc; 835633c4283SRichard Henderson break; 836633c4283SRichard Henderson default: 837633c4283SRichard Henderson g_assert_not_reached(); 838633c4283SRichard Henderson } 839fcf5ef2aSThomas Huth } else { 840fcf5ef2aSThomas Huth dc->pc = dc->npc; 841fcf5ef2aSThomas Huth } 842fcf5ef2aSThomas Huth } 843fcf5ef2aSThomas Huth 844fcf5ef2aSThomas Huth static void gen_compare(DisasCompare *cmp, bool xcc, unsigned int cond, 845fcf5ef2aSThomas Huth DisasContext *dc) 846fcf5ef2aSThomas Huth { 847b597eedcSRichard Henderson TCGv t1; 848fcf5ef2aSThomas Huth 8492a1905c7SRichard Henderson cmp->c1 = t1 = tcg_temp_new(); 850c8507ebfSRichard Henderson cmp->c2 = 0; 8512a1905c7SRichard Henderson 8522a1905c7SRichard Henderson switch (cond & 7) { 8532a1905c7SRichard Henderson case 0x0: /* never */ 8542a1905c7SRichard Henderson cmp->cond = TCG_COND_NEVER; 855c8507ebfSRichard Henderson cmp->c1 = tcg_constant_tl(0); 856fcf5ef2aSThomas Huth break; 8572a1905c7SRichard Henderson 8582a1905c7SRichard Henderson case 0x1: /* eq: Z */ 8592a1905c7SRichard Henderson cmp->cond = TCG_COND_EQ; 8602a1905c7SRichard Henderson if (TARGET_LONG_BITS == 32 || xcc) { 8612a1905c7SRichard Henderson tcg_gen_mov_tl(t1, cpu_cc_Z); 8622a1905c7SRichard Henderson } else { 8632a1905c7SRichard Henderson tcg_gen_ext32u_tl(t1, cpu_icc_Z); 8642a1905c7SRichard Henderson } 8652a1905c7SRichard Henderson break; 8662a1905c7SRichard Henderson 8672a1905c7SRichard Henderson case 0x2: /* le: Z | (N ^ V) */ 8682a1905c7SRichard Henderson /* 8692a1905c7SRichard Henderson * Simplify: 8702a1905c7SRichard Henderson * cc_Z || (N ^ V) < 0 NE 8712a1905c7SRichard Henderson * cc_Z && !((N ^ V) < 0) EQ 8722a1905c7SRichard Henderson * cc_Z & ~((N ^ V) >> TLB) EQ 8732a1905c7SRichard Henderson */ 8742a1905c7SRichard Henderson cmp->cond = TCG_COND_EQ; 8752a1905c7SRichard Henderson tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V); 8762a1905c7SRichard Henderson tcg_gen_sextract_tl(t1, t1, xcc ? 63 : 31, 1); 8772a1905c7SRichard Henderson tcg_gen_andc_tl(t1, xcc ? cpu_cc_Z : cpu_icc_Z, t1); 8782a1905c7SRichard Henderson if (TARGET_LONG_BITS == 64 && !xcc) { 8792a1905c7SRichard Henderson tcg_gen_ext32u_tl(t1, t1); 8802a1905c7SRichard Henderson } 8812a1905c7SRichard Henderson break; 8822a1905c7SRichard Henderson 8832a1905c7SRichard Henderson case 0x3: /* lt: N ^ V */ 8842a1905c7SRichard Henderson cmp->cond = TCG_COND_LT; 8852a1905c7SRichard Henderson tcg_gen_xor_tl(t1, cpu_cc_N, cpu_cc_V); 8862a1905c7SRichard Henderson if (TARGET_LONG_BITS == 64 && !xcc) { 8872a1905c7SRichard Henderson tcg_gen_ext32s_tl(t1, t1); 8882a1905c7SRichard Henderson } 8892a1905c7SRichard Henderson break; 8902a1905c7SRichard Henderson 8912a1905c7SRichard Henderson case 0x4: /* leu: Z | C */ 8922a1905c7SRichard Henderson /* 8932a1905c7SRichard Henderson * Simplify: 8942a1905c7SRichard Henderson * cc_Z == 0 || cc_C != 0 NE 8952a1905c7SRichard Henderson * cc_Z != 0 && cc_C == 0 EQ 8962a1905c7SRichard Henderson * cc_Z & (cc_C ? 0 : -1) EQ 8972a1905c7SRichard Henderson * cc_Z & (cc_C - 1) EQ 8982a1905c7SRichard Henderson */ 8992a1905c7SRichard Henderson cmp->cond = TCG_COND_EQ; 9002a1905c7SRichard Henderson if (TARGET_LONG_BITS == 32 || xcc) { 9012a1905c7SRichard Henderson tcg_gen_subi_tl(t1, cpu_cc_C, 1); 9022a1905c7SRichard Henderson tcg_gen_and_tl(t1, t1, cpu_cc_Z); 9032a1905c7SRichard Henderson } else { 9042a1905c7SRichard Henderson tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1); 9052a1905c7SRichard Henderson tcg_gen_subi_tl(t1, t1, 1); 9062a1905c7SRichard Henderson tcg_gen_and_tl(t1, t1, cpu_icc_Z); 9072a1905c7SRichard Henderson tcg_gen_ext32u_tl(t1, t1); 9082a1905c7SRichard Henderson } 9092a1905c7SRichard Henderson break; 9102a1905c7SRichard Henderson 9112a1905c7SRichard Henderson case 0x5: /* ltu: C */ 9122a1905c7SRichard Henderson cmp->cond = TCG_COND_NE; 9132a1905c7SRichard Henderson if (TARGET_LONG_BITS == 32 || xcc) { 9142a1905c7SRichard Henderson tcg_gen_mov_tl(t1, cpu_cc_C); 9152a1905c7SRichard Henderson } else { 9162a1905c7SRichard Henderson tcg_gen_extract_tl(t1, cpu_icc_C, 32, 1); 9172a1905c7SRichard Henderson } 9182a1905c7SRichard Henderson break; 9192a1905c7SRichard Henderson 9202a1905c7SRichard Henderson case 0x6: /* neg: N */ 9212a1905c7SRichard Henderson cmp->cond = TCG_COND_LT; 9222a1905c7SRichard Henderson if (TARGET_LONG_BITS == 32 || xcc) { 9232a1905c7SRichard Henderson tcg_gen_mov_tl(t1, cpu_cc_N); 9242a1905c7SRichard Henderson } else { 9252a1905c7SRichard Henderson tcg_gen_ext32s_tl(t1, cpu_cc_N); 9262a1905c7SRichard Henderson } 9272a1905c7SRichard Henderson break; 9282a1905c7SRichard Henderson 9292a1905c7SRichard Henderson case 0x7: /* vs: V */ 9302a1905c7SRichard Henderson cmp->cond = TCG_COND_LT; 9312a1905c7SRichard Henderson if (TARGET_LONG_BITS == 32 || xcc) { 9322a1905c7SRichard Henderson tcg_gen_mov_tl(t1, cpu_cc_V); 9332a1905c7SRichard Henderson } else { 9342a1905c7SRichard Henderson tcg_gen_ext32s_tl(t1, cpu_cc_V); 9352a1905c7SRichard Henderson } 9362a1905c7SRichard Henderson break; 9372a1905c7SRichard Henderson } 9382a1905c7SRichard Henderson if (cond & 8) { 9392a1905c7SRichard Henderson cmp->cond = tcg_invert_cond(cmp->cond); 940fcf5ef2aSThomas Huth } 941fcf5ef2aSThomas Huth } 942fcf5ef2aSThomas Huth 943fcf5ef2aSThomas Huth static void gen_fcompare(DisasCompare *cmp, unsigned int cc, unsigned int cond) 944fcf5ef2aSThomas Huth { 945d8c5b92fSRichard Henderson TCGv_i32 fcc = cpu_fcc[cc]; 946d8c5b92fSRichard Henderson TCGv_i32 c1 = fcc; 947d8c5b92fSRichard Henderson int c2 = 0; 948d8c5b92fSRichard Henderson TCGCond tcond; 949fcf5ef2aSThomas Huth 950d8c5b92fSRichard Henderson /* 951d8c5b92fSRichard Henderson * FCC values: 952d8c5b92fSRichard Henderson * 0 = 953d8c5b92fSRichard Henderson * 1 < 954d8c5b92fSRichard Henderson * 2 > 955d8c5b92fSRichard Henderson * 3 unordered 956d8c5b92fSRichard Henderson */ 957d8c5b92fSRichard Henderson switch (cond & 7) { 958d8c5b92fSRichard Henderson case 0x0: /* fbn */ 959d8c5b92fSRichard Henderson tcond = TCG_COND_NEVER; 960fcf5ef2aSThomas Huth break; 961d8c5b92fSRichard Henderson case 0x1: /* fbne : !0 */ 962d8c5b92fSRichard Henderson tcond = TCG_COND_NE; 963fcf5ef2aSThomas Huth break; 964d8c5b92fSRichard Henderson case 0x2: /* fblg : 1 or 2 */ 965d8c5b92fSRichard Henderson /* fcc in {1,2} - 1 -> fcc in {0,1} */ 966d8c5b92fSRichard Henderson c1 = tcg_temp_new_i32(); 967d8c5b92fSRichard Henderson tcg_gen_addi_i32(c1, fcc, -1); 968d8c5b92fSRichard Henderson c2 = 1; 969d8c5b92fSRichard Henderson tcond = TCG_COND_LEU; 970fcf5ef2aSThomas Huth break; 971d8c5b92fSRichard Henderson case 0x3: /* fbul : 1 or 3 */ 972d8c5b92fSRichard Henderson c1 = tcg_temp_new_i32(); 973d8c5b92fSRichard Henderson tcg_gen_andi_i32(c1, fcc, 1); 974d8c5b92fSRichard Henderson tcond = TCG_COND_NE; 975d8c5b92fSRichard Henderson break; 976d8c5b92fSRichard Henderson case 0x4: /* fbl : 1 */ 977d8c5b92fSRichard Henderson c2 = 1; 978d8c5b92fSRichard Henderson tcond = TCG_COND_EQ; 979d8c5b92fSRichard Henderson break; 980d8c5b92fSRichard Henderson case 0x5: /* fbug : 2 or 3 */ 981d8c5b92fSRichard Henderson c2 = 2; 982d8c5b92fSRichard Henderson tcond = TCG_COND_GEU; 983d8c5b92fSRichard Henderson break; 984d8c5b92fSRichard Henderson case 0x6: /* fbg : 2 */ 985d8c5b92fSRichard Henderson c2 = 2; 986d8c5b92fSRichard Henderson tcond = TCG_COND_EQ; 987d8c5b92fSRichard Henderson break; 988d8c5b92fSRichard Henderson case 0x7: /* fbu : 3 */ 989d8c5b92fSRichard Henderson c2 = 3; 990d8c5b92fSRichard Henderson tcond = TCG_COND_EQ; 991fcf5ef2aSThomas Huth break; 992fcf5ef2aSThomas Huth } 993d8c5b92fSRichard Henderson if (cond & 8) { 994d8c5b92fSRichard Henderson tcond = tcg_invert_cond(tcond); 995fcf5ef2aSThomas Huth } 996d8c5b92fSRichard Henderson 997d8c5b92fSRichard Henderson cmp->cond = tcond; 998d8c5b92fSRichard Henderson cmp->c2 = c2; 999d8c5b92fSRichard Henderson cmp->c1 = tcg_temp_new(); 1000d8c5b92fSRichard Henderson tcg_gen_extu_i32_tl(cmp->c1, c1); 1001fcf5ef2aSThomas Huth } 1002fcf5ef2aSThomas Huth 10032c4f56c9SRichard Henderson static bool gen_compare_reg(DisasCompare *cmp, int cond, TCGv r_src) 10042c4f56c9SRichard Henderson { 10052c4f56c9SRichard Henderson static const TCGCond cond_reg[4] = { 1006ab9ffe98SRichard Henderson TCG_COND_NEVER, /* reserved */ 1007fcf5ef2aSThomas Huth TCG_COND_EQ, 1008fcf5ef2aSThomas Huth TCG_COND_LE, 1009fcf5ef2aSThomas Huth TCG_COND_LT, 1010fcf5ef2aSThomas Huth }; 10112c4f56c9SRichard Henderson TCGCond tcond; 1012fcf5ef2aSThomas Huth 10132c4f56c9SRichard Henderson if ((cond & 3) == 0) { 10142c4f56c9SRichard Henderson return false; 10152c4f56c9SRichard Henderson } 10162c4f56c9SRichard Henderson tcond = cond_reg[cond & 3]; 10172c4f56c9SRichard Henderson if (cond & 4) { 10182c4f56c9SRichard Henderson tcond = tcg_invert_cond(tcond); 10192c4f56c9SRichard Henderson } 10202c4f56c9SRichard Henderson 10212c4f56c9SRichard Henderson cmp->cond = tcond; 1022816f89b7SRichard Henderson cmp->c1 = tcg_temp_new(); 1023c8507ebfSRichard Henderson cmp->c2 = 0; 1024816f89b7SRichard Henderson tcg_gen_mov_tl(cmp->c1, r_src); 10252c4f56c9SRichard Henderson return true; 1026fcf5ef2aSThomas Huth } 1027fcf5ef2aSThomas Huth 1028baf3dbf2SRichard Henderson static void gen_op_clear_ieee_excp_and_FTT(void) 1029baf3dbf2SRichard Henderson { 10303590f01eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(0), tcg_env, 10313590f01eSRichard Henderson offsetof(CPUSPARCState, fsr_cexc_ftt)); 1032baf3dbf2SRichard Henderson } 1033baf3dbf2SRichard Henderson 1034baf3dbf2SRichard Henderson static void gen_op_fmovs(TCGv_i32 dst, TCGv_i32 src) 1035baf3dbf2SRichard Henderson { 1036baf3dbf2SRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 1037baf3dbf2SRichard Henderson tcg_gen_mov_i32(dst, src); 1038baf3dbf2SRichard Henderson } 1039baf3dbf2SRichard Henderson 1040baf3dbf2SRichard Henderson static void gen_op_fnegs(TCGv_i32 dst, TCGv_i32 src) 1041baf3dbf2SRichard Henderson { 1042baf3dbf2SRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 1043daf457d4SRichard Henderson tcg_gen_xori_i32(dst, src, 1u << 31); 1044baf3dbf2SRichard Henderson } 1045baf3dbf2SRichard Henderson 1046baf3dbf2SRichard Henderson static void gen_op_fabss(TCGv_i32 dst, TCGv_i32 src) 1047baf3dbf2SRichard Henderson { 1048baf3dbf2SRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 1049daf457d4SRichard Henderson tcg_gen_andi_i32(dst, src, ~(1u << 31)); 1050baf3dbf2SRichard Henderson } 1051baf3dbf2SRichard Henderson 1052c6d83e4fSRichard Henderson static void gen_op_fmovd(TCGv_i64 dst, TCGv_i64 src) 1053c6d83e4fSRichard Henderson { 1054c6d83e4fSRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 1055c6d83e4fSRichard Henderson tcg_gen_mov_i64(dst, src); 1056c6d83e4fSRichard Henderson } 1057c6d83e4fSRichard Henderson 1058c6d83e4fSRichard Henderson static void gen_op_fnegd(TCGv_i64 dst, TCGv_i64 src) 1059c6d83e4fSRichard Henderson { 1060c6d83e4fSRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 1061daf457d4SRichard Henderson tcg_gen_xori_i64(dst, src, 1ull << 63); 1062c6d83e4fSRichard Henderson } 1063c6d83e4fSRichard Henderson 1064c6d83e4fSRichard Henderson static void gen_op_fabsd(TCGv_i64 dst, TCGv_i64 src) 1065c6d83e4fSRichard Henderson { 1066c6d83e4fSRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 1067daf457d4SRichard Henderson tcg_gen_andi_i64(dst, src, ~(1ull << 63)); 1068daf457d4SRichard Henderson } 1069daf457d4SRichard Henderson 1070daf457d4SRichard Henderson static void gen_op_fnegq(TCGv_i128 dst, TCGv_i128 src) 1071daf457d4SRichard Henderson { 1072daf457d4SRichard Henderson TCGv_i64 l = tcg_temp_new_i64(); 1073daf457d4SRichard Henderson TCGv_i64 h = tcg_temp_new_i64(); 1074daf457d4SRichard Henderson 1075daf457d4SRichard Henderson tcg_gen_extr_i128_i64(l, h, src); 1076daf457d4SRichard Henderson tcg_gen_xori_i64(h, h, 1ull << 63); 1077daf457d4SRichard Henderson tcg_gen_concat_i64_i128(dst, l, h); 1078daf457d4SRichard Henderson } 1079daf457d4SRichard Henderson 1080daf457d4SRichard Henderson static void gen_op_fabsq(TCGv_i128 dst, TCGv_i128 src) 1081daf457d4SRichard Henderson { 1082daf457d4SRichard Henderson TCGv_i64 l = tcg_temp_new_i64(); 1083daf457d4SRichard Henderson TCGv_i64 h = tcg_temp_new_i64(); 1084daf457d4SRichard Henderson 1085daf457d4SRichard Henderson tcg_gen_extr_i128_i64(l, h, src); 1086daf457d4SRichard Henderson tcg_gen_andi_i64(h, h, ~(1ull << 63)); 1087daf457d4SRichard Henderson tcg_gen_concat_i64_i128(dst, l, h); 1088c6d83e4fSRichard Henderson } 1089c6d83e4fSRichard Henderson 10903590f01eSRichard Henderson static void gen_op_fpexception_im(DisasContext *dc, int ftt) 1091fcf5ef2aSThomas Huth { 10923590f01eSRichard Henderson /* 10933590f01eSRichard Henderson * CEXC is only set when succesfully completing an FPop, 10943590f01eSRichard Henderson * or when raising FSR_FTT_IEEE_EXCP, i.e. check_ieee_exception. 10953590f01eSRichard Henderson * Thus we can simply store FTT into this field. 10963590f01eSRichard Henderson */ 10973590f01eSRichard Henderson tcg_gen_st_i32(tcg_constant_i32(ftt), tcg_env, 10983590f01eSRichard Henderson offsetof(CPUSPARCState, fsr_cexc_ftt)); 1099fcf5ef2aSThomas Huth gen_exception(dc, TT_FP_EXCP); 1100fcf5ef2aSThomas Huth } 1101fcf5ef2aSThomas Huth 1102fcf5ef2aSThomas Huth static int gen_trap_ifnofpu(DisasContext *dc) 1103fcf5ef2aSThomas Huth { 1104fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 1105fcf5ef2aSThomas Huth if (!dc->fpu_enabled) { 1106fcf5ef2aSThomas Huth gen_exception(dc, TT_NFPU_INSN); 1107fcf5ef2aSThomas Huth return 1; 1108fcf5ef2aSThomas Huth } 1109fcf5ef2aSThomas Huth #endif 1110fcf5ef2aSThomas Huth return 0; 1111fcf5ef2aSThomas Huth } 1112fcf5ef2aSThomas Huth 1113fcf5ef2aSThomas Huth /* asi moves */ 1114fcf5ef2aSThomas Huth typedef enum { 1115fcf5ef2aSThomas Huth GET_ASI_HELPER, 1116fcf5ef2aSThomas Huth GET_ASI_EXCP, 1117fcf5ef2aSThomas Huth GET_ASI_DIRECT, 1118fcf5ef2aSThomas Huth GET_ASI_DTWINX, 1119fcf5ef2aSThomas Huth GET_ASI_BLOCK, 1120fcf5ef2aSThomas Huth GET_ASI_SHORT, 1121fcf5ef2aSThomas Huth GET_ASI_BCOPY, 1122fcf5ef2aSThomas Huth GET_ASI_BFILL, 1123fcf5ef2aSThomas Huth } ASIType; 1124fcf5ef2aSThomas Huth 1125fcf5ef2aSThomas Huth typedef struct { 1126fcf5ef2aSThomas Huth ASIType type; 1127fcf5ef2aSThomas Huth int asi; 1128fcf5ef2aSThomas Huth int mem_idx; 112914776ab5STony Nguyen MemOp memop; 1130fcf5ef2aSThomas Huth } DisasASI; 1131fcf5ef2aSThomas Huth 1132811cc0b0SRichard Henderson /* 1133811cc0b0SRichard Henderson * Build DisasASI. 1134811cc0b0SRichard Henderson * For asi == -1, treat as non-asi. 1135811cc0b0SRichard Henderson * For ask == -2, treat as immediate offset (v8 error, v9 %asi). 1136811cc0b0SRichard Henderson */ 1137811cc0b0SRichard Henderson static DisasASI resolve_asi(DisasContext *dc, int asi, MemOp memop) 1138fcf5ef2aSThomas Huth { 1139fcf5ef2aSThomas Huth ASIType type = GET_ASI_HELPER; 1140fcf5ef2aSThomas Huth int mem_idx = dc->mem_idx; 1141fcf5ef2aSThomas Huth 1142811cc0b0SRichard Henderson if (asi == -1) { 1143811cc0b0SRichard Henderson /* Artificial "non-asi" case. */ 1144811cc0b0SRichard Henderson type = GET_ASI_DIRECT; 1145811cc0b0SRichard Henderson goto done; 1146811cc0b0SRichard Henderson } 1147811cc0b0SRichard Henderson 1148fcf5ef2aSThomas Huth #ifndef TARGET_SPARC64 1149fcf5ef2aSThomas Huth /* Before v9, all asis are immediate and privileged. */ 1150811cc0b0SRichard Henderson if (asi < 0) { 1151fcf5ef2aSThomas Huth gen_exception(dc, TT_ILL_INSN); 1152fcf5ef2aSThomas Huth type = GET_ASI_EXCP; 1153fcf5ef2aSThomas Huth } else if (supervisor(dc) 1154fcf5ef2aSThomas Huth /* Note that LEON accepts ASI_USERDATA in user mode, for 1155fcf5ef2aSThomas Huth use with CASA. Also note that previous versions of 1156fcf5ef2aSThomas Huth QEMU allowed (and old versions of gcc emitted) ASI_P 1157fcf5ef2aSThomas Huth for LEON, which is incorrect. */ 1158fcf5ef2aSThomas Huth || (asi == ASI_USERDATA 1159fcf5ef2aSThomas Huth && (dc->def->features & CPU_FEATURE_CASA))) { 1160fcf5ef2aSThomas Huth switch (asi) { 1161fcf5ef2aSThomas Huth case ASI_USERDATA: /* User data access */ 1162fcf5ef2aSThomas Huth mem_idx = MMU_USER_IDX; 1163fcf5ef2aSThomas Huth type = GET_ASI_DIRECT; 1164fcf5ef2aSThomas Huth break; 1165fcf5ef2aSThomas Huth case ASI_KERNELDATA: /* Supervisor data access */ 1166fcf5ef2aSThomas Huth mem_idx = MMU_KERNEL_IDX; 1167fcf5ef2aSThomas Huth type = GET_ASI_DIRECT; 1168fcf5ef2aSThomas Huth break; 1169fcf5ef2aSThomas Huth case ASI_M_BYPASS: /* MMU passthrough */ 1170fcf5ef2aSThomas Huth case ASI_LEON_BYPASS: /* LEON MMU passthrough */ 1171fcf5ef2aSThomas Huth mem_idx = MMU_PHYS_IDX; 1172fcf5ef2aSThomas Huth type = GET_ASI_DIRECT; 1173fcf5ef2aSThomas Huth break; 1174fcf5ef2aSThomas Huth case ASI_M_BCOPY: /* Block copy, sta access */ 1175fcf5ef2aSThomas Huth mem_idx = MMU_KERNEL_IDX; 1176fcf5ef2aSThomas Huth type = GET_ASI_BCOPY; 1177fcf5ef2aSThomas Huth break; 1178fcf5ef2aSThomas Huth case ASI_M_BFILL: /* Block fill, stda access */ 1179fcf5ef2aSThomas Huth mem_idx = MMU_KERNEL_IDX; 1180fcf5ef2aSThomas Huth type = GET_ASI_BFILL; 1181fcf5ef2aSThomas Huth break; 1182fcf5ef2aSThomas Huth } 11836e10f37cSKONRAD Frederic 11846e10f37cSKONRAD Frederic /* MMU_PHYS_IDX is used when the MMU is disabled to passthrough the 11856e10f37cSKONRAD Frederic * permissions check in get_physical_address(..). 11866e10f37cSKONRAD Frederic */ 11876e10f37cSKONRAD Frederic mem_idx = (dc->mem_idx == MMU_PHYS_IDX) ? MMU_PHYS_IDX : mem_idx; 1188fcf5ef2aSThomas Huth } else { 1189fcf5ef2aSThomas Huth gen_exception(dc, TT_PRIV_INSN); 1190fcf5ef2aSThomas Huth type = GET_ASI_EXCP; 1191fcf5ef2aSThomas Huth } 1192fcf5ef2aSThomas Huth #else 1193811cc0b0SRichard Henderson if (asi < 0) { 1194fcf5ef2aSThomas Huth asi = dc->asi; 1195fcf5ef2aSThomas Huth } 1196fcf5ef2aSThomas Huth /* With v9, all asis below 0x80 are privileged. */ 1197fcf5ef2aSThomas Huth /* ??? We ought to check cpu_has_hypervisor, but we didn't copy 1198fcf5ef2aSThomas Huth down that bit into DisasContext. For the moment that's ok, 1199fcf5ef2aSThomas Huth since the direct implementations below doesn't have any ASIs 1200fcf5ef2aSThomas Huth in the restricted [0x30, 0x7f] range, and the check will be 1201fcf5ef2aSThomas Huth done properly in the helper. */ 1202fcf5ef2aSThomas Huth if (!supervisor(dc) && asi < 0x80) { 1203fcf5ef2aSThomas Huth gen_exception(dc, TT_PRIV_ACT); 1204fcf5ef2aSThomas Huth type = GET_ASI_EXCP; 1205fcf5ef2aSThomas Huth } else { 1206fcf5ef2aSThomas Huth switch (asi) { 1207fcf5ef2aSThomas Huth case ASI_REAL: /* Bypass */ 1208fcf5ef2aSThomas Huth case ASI_REAL_IO: /* Bypass, non-cacheable */ 1209fcf5ef2aSThomas Huth case ASI_REAL_L: /* Bypass LE */ 1210fcf5ef2aSThomas Huth case ASI_REAL_IO_L: /* Bypass, non-cacheable LE */ 1211fcf5ef2aSThomas Huth case ASI_TWINX_REAL: /* Real address, twinx */ 1212fcf5ef2aSThomas Huth case ASI_TWINX_REAL_L: /* Real address, twinx, LE */ 1213fcf5ef2aSThomas Huth case ASI_QUAD_LDD_PHYS: 1214fcf5ef2aSThomas Huth case ASI_QUAD_LDD_PHYS_L: 1215fcf5ef2aSThomas Huth mem_idx = MMU_PHYS_IDX; 1216fcf5ef2aSThomas Huth break; 1217fcf5ef2aSThomas Huth case ASI_N: /* Nucleus */ 1218fcf5ef2aSThomas Huth case ASI_NL: /* Nucleus LE */ 1219fcf5ef2aSThomas Huth case ASI_TWINX_N: 1220fcf5ef2aSThomas Huth case ASI_TWINX_NL: 1221fcf5ef2aSThomas Huth case ASI_NUCLEUS_QUAD_LDD: 1222fcf5ef2aSThomas Huth case ASI_NUCLEUS_QUAD_LDD_L: 12239a10756dSArtyom Tarasenko if (hypervisor(dc)) { 122484f8f587SArtyom Tarasenko mem_idx = MMU_PHYS_IDX; 12259a10756dSArtyom Tarasenko } else { 1226fcf5ef2aSThomas Huth mem_idx = MMU_NUCLEUS_IDX; 12279a10756dSArtyom Tarasenko } 1228fcf5ef2aSThomas Huth break; 1229fcf5ef2aSThomas Huth case ASI_AIUP: /* As if user primary */ 1230fcf5ef2aSThomas Huth case ASI_AIUPL: /* As if user primary LE */ 1231fcf5ef2aSThomas Huth case ASI_TWINX_AIUP: 1232fcf5ef2aSThomas Huth case ASI_TWINX_AIUP_L: 1233fcf5ef2aSThomas Huth case ASI_BLK_AIUP_4V: 1234fcf5ef2aSThomas Huth case ASI_BLK_AIUP_L_4V: 1235fcf5ef2aSThomas Huth case ASI_BLK_AIUP: 1236fcf5ef2aSThomas Huth case ASI_BLK_AIUPL: 1237fcf5ef2aSThomas Huth mem_idx = MMU_USER_IDX; 1238fcf5ef2aSThomas Huth break; 1239fcf5ef2aSThomas Huth case ASI_AIUS: /* As if user secondary */ 1240fcf5ef2aSThomas Huth case ASI_AIUSL: /* As if user secondary LE */ 1241fcf5ef2aSThomas Huth case ASI_TWINX_AIUS: 1242fcf5ef2aSThomas Huth case ASI_TWINX_AIUS_L: 1243fcf5ef2aSThomas Huth case ASI_BLK_AIUS_4V: 1244fcf5ef2aSThomas Huth case ASI_BLK_AIUS_L_4V: 1245fcf5ef2aSThomas Huth case ASI_BLK_AIUS: 1246fcf5ef2aSThomas Huth case ASI_BLK_AIUSL: 1247fcf5ef2aSThomas Huth mem_idx = MMU_USER_SECONDARY_IDX; 1248fcf5ef2aSThomas Huth break; 1249fcf5ef2aSThomas Huth case ASI_S: /* Secondary */ 1250fcf5ef2aSThomas Huth case ASI_SL: /* Secondary LE */ 1251fcf5ef2aSThomas Huth case ASI_TWINX_S: 1252fcf5ef2aSThomas Huth case ASI_TWINX_SL: 1253fcf5ef2aSThomas Huth case ASI_BLK_COMMIT_S: 1254fcf5ef2aSThomas Huth case ASI_BLK_S: 1255fcf5ef2aSThomas Huth case ASI_BLK_SL: 1256fcf5ef2aSThomas Huth case ASI_FL8_S: 1257fcf5ef2aSThomas Huth case ASI_FL8_SL: 1258fcf5ef2aSThomas Huth case ASI_FL16_S: 1259fcf5ef2aSThomas Huth case ASI_FL16_SL: 1260fcf5ef2aSThomas Huth if (mem_idx == MMU_USER_IDX) { 1261fcf5ef2aSThomas Huth mem_idx = MMU_USER_SECONDARY_IDX; 1262fcf5ef2aSThomas Huth } else if (mem_idx == MMU_KERNEL_IDX) { 1263fcf5ef2aSThomas Huth mem_idx = MMU_KERNEL_SECONDARY_IDX; 1264fcf5ef2aSThomas Huth } 1265fcf5ef2aSThomas Huth break; 1266fcf5ef2aSThomas Huth case ASI_P: /* Primary */ 1267fcf5ef2aSThomas Huth case ASI_PL: /* Primary LE */ 1268fcf5ef2aSThomas Huth case ASI_TWINX_P: 1269fcf5ef2aSThomas Huth case ASI_TWINX_PL: 1270fcf5ef2aSThomas Huth case ASI_BLK_COMMIT_P: 1271fcf5ef2aSThomas Huth case ASI_BLK_P: 1272fcf5ef2aSThomas Huth case ASI_BLK_PL: 1273fcf5ef2aSThomas Huth case ASI_FL8_P: 1274fcf5ef2aSThomas Huth case ASI_FL8_PL: 1275fcf5ef2aSThomas Huth case ASI_FL16_P: 1276fcf5ef2aSThomas Huth case ASI_FL16_PL: 1277fcf5ef2aSThomas Huth break; 1278fcf5ef2aSThomas Huth } 1279fcf5ef2aSThomas Huth switch (asi) { 1280fcf5ef2aSThomas Huth case ASI_REAL: 1281fcf5ef2aSThomas Huth case ASI_REAL_IO: 1282fcf5ef2aSThomas Huth case ASI_REAL_L: 1283fcf5ef2aSThomas Huth case ASI_REAL_IO_L: 1284fcf5ef2aSThomas Huth case ASI_N: 1285fcf5ef2aSThomas Huth case ASI_NL: 1286fcf5ef2aSThomas Huth case ASI_AIUP: 1287fcf5ef2aSThomas Huth case ASI_AIUPL: 1288fcf5ef2aSThomas Huth case ASI_AIUS: 1289fcf5ef2aSThomas Huth case ASI_AIUSL: 1290fcf5ef2aSThomas Huth case ASI_S: 1291fcf5ef2aSThomas Huth case ASI_SL: 1292fcf5ef2aSThomas Huth case ASI_P: 1293fcf5ef2aSThomas Huth case ASI_PL: 1294fcf5ef2aSThomas Huth type = GET_ASI_DIRECT; 1295fcf5ef2aSThomas Huth break; 1296fcf5ef2aSThomas Huth case ASI_TWINX_REAL: 1297fcf5ef2aSThomas Huth case ASI_TWINX_REAL_L: 1298fcf5ef2aSThomas Huth case ASI_TWINX_N: 1299fcf5ef2aSThomas Huth case ASI_TWINX_NL: 1300fcf5ef2aSThomas Huth case ASI_TWINX_AIUP: 1301fcf5ef2aSThomas Huth case ASI_TWINX_AIUP_L: 1302fcf5ef2aSThomas Huth case ASI_TWINX_AIUS: 1303fcf5ef2aSThomas Huth case ASI_TWINX_AIUS_L: 1304fcf5ef2aSThomas Huth case ASI_TWINX_P: 1305fcf5ef2aSThomas Huth case ASI_TWINX_PL: 1306fcf5ef2aSThomas Huth case ASI_TWINX_S: 1307fcf5ef2aSThomas Huth case ASI_TWINX_SL: 1308fcf5ef2aSThomas Huth case ASI_QUAD_LDD_PHYS: 1309fcf5ef2aSThomas Huth case ASI_QUAD_LDD_PHYS_L: 1310fcf5ef2aSThomas Huth case ASI_NUCLEUS_QUAD_LDD: 1311fcf5ef2aSThomas Huth case ASI_NUCLEUS_QUAD_LDD_L: 1312fcf5ef2aSThomas Huth type = GET_ASI_DTWINX; 1313fcf5ef2aSThomas Huth break; 1314fcf5ef2aSThomas Huth case ASI_BLK_COMMIT_P: 1315fcf5ef2aSThomas Huth case ASI_BLK_COMMIT_S: 1316fcf5ef2aSThomas Huth case ASI_BLK_AIUP_4V: 1317fcf5ef2aSThomas Huth case ASI_BLK_AIUP_L_4V: 1318fcf5ef2aSThomas Huth case ASI_BLK_AIUP: 1319fcf5ef2aSThomas Huth case ASI_BLK_AIUPL: 1320fcf5ef2aSThomas Huth case ASI_BLK_AIUS_4V: 1321fcf5ef2aSThomas Huth case ASI_BLK_AIUS_L_4V: 1322fcf5ef2aSThomas Huth case ASI_BLK_AIUS: 1323fcf5ef2aSThomas Huth case ASI_BLK_AIUSL: 1324fcf5ef2aSThomas Huth case ASI_BLK_S: 1325fcf5ef2aSThomas Huth case ASI_BLK_SL: 1326fcf5ef2aSThomas Huth case ASI_BLK_P: 1327fcf5ef2aSThomas Huth case ASI_BLK_PL: 1328fcf5ef2aSThomas Huth type = GET_ASI_BLOCK; 1329fcf5ef2aSThomas Huth break; 1330fcf5ef2aSThomas Huth case ASI_FL8_S: 1331fcf5ef2aSThomas Huth case ASI_FL8_SL: 1332fcf5ef2aSThomas Huth case ASI_FL8_P: 1333fcf5ef2aSThomas Huth case ASI_FL8_PL: 1334fcf5ef2aSThomas Huth memop = MO_UB; 1335fcf5ef2aSThomas Huth type = GET_ASI_SHORT; 1336fcf5ef2aSThomas Huth break; 1337fcf5ef2aSThomas Huth case ASI_FL16_S: 1338fcf5ef2aSThomas Huth case ASI_FL16_SL: 1339fcf5ef2aSThomas Huth case ASI_FL16_P: 1340fcf5ef2aSThomas Huth case ASI_FL16_PL: 1341fcf5ef2aSThomas Huth memop = MO_TEUW; 1342fcf5ef2aSThomas Huth type = GET_ASI_SHORT; 1343fcf5ef2aSThomas Huth break; 1344fcf5ef2aSThomas Huth } 1345fcf5ef2aSThomas Huth /* The little-endian asis all have bit 3 set. */ 1346fcf5ef2aSThomas Huth if (asi & 8) { 1347fcf5ef2aSThomas Huth memop ^= MO_BSWAP; 1348fcf5ef2aSThomas Huth } 1349fcf5ef2aSThomas Huth } 1350fcf5ef2aSThomas Huth #endif 1351fcf5ef2aSThomas Huth 1352811cc0b0SRichard Henderson done: 1353fcf5ef2aSThomas Huth return (DisasASI){ type, asi, mem_idx, memop }; 1354fcf5ef2aSThomas Huth } 1355fcf5ef2aSThomas Huth 1356a76779eeSRichard Henderson #if defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64) 1357a76779eeSRichard Henderson static void gen_helper_ld_asi(TCGv_i64 r, TCGv_env e, TCGv a, 1358a76779eeSRichard Henderson TCGv_i32 asi, TCGv_i32 mop) 1359a76779eeSRichard Henderson { 1360a76779eeSRichard Henderson g_assert_not_reached(); 1361a76779eeSRichard Henderson } 1362a76779eeSRichard Henderson 1363a76779eeSRichard Henderson static void gen_helper_st_asi(TCGv_env e, TCGv a, TCGv_i64 r, 1364a76779eeSRichard Henderson TCGv_i32 asi, TCGv_i32 mop) 1365a76779eeSRichard Henderson { 1366a76779eeSRichard Henderson g_assert_not_reached(); 1367a76779eeSRichard Henderson } 1368a76779eeSRichard Henderson #endif 1369a76779eeSRichard Henderson 137042071fc1SRichard Henderson static void gen_ld_asi(DisasContext *dc, DisasASI *da, TCGv dst, TCGv addr) 1371fcf5ef2aSThomas Huth { 1372c03a0fd1SRichard Henderson switch (da->type) { 1373fcf5ef2aSThomas Huth case GET_ASI_EXCP: 1374fcf5ef2aSThomas Huth break; 1375fcf5ef2aSThomas Huth case GET_ASI_DTWINX: /* Reserved for ldda. */ 1376fcf5ef2aSThomas Huth gen_exception(dc, TT_ILL_INSN); 1377fcf5ef2aSThomas Huth break; 1378fcf5ef2aSThomas Huth case GET_ASI_DIRECT: 1379c03a0fd1SRichard Henderson tcg_gen_qemu_ld_tl(dst, addr, da->mem_idx, da->memop | MO_ALIGN); 1380fcf5ef2aSThomas Huth break; 1381fcf5ef2aSThomas Huth default: 1382fcf5ef2aSThomas Huth { 1383c03a0fd1SRichard Henderson TCGv_i32 r_asi = tcg_constant_i32(da->asi); 1384c03a0fd1SRichard Henderson TCGv_i32 r_mop = tcg_constant_i32(da->memop | MO_ALIGN); 1385fcf5ef2aSThomas Huth 1386fcf5ef2aSThomas Huth save_state(dc); 1387fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 1388ad75a51eSRichard Henderson gen_helper_ld_asi(dst, tcg_env, addr, r_asi, r_mop); 1389fcf5ef2aSThomas Huth #else 1390fcf5ef2aSThomas Huth { 1391fcf5ef2aSThomas Huth TCGv_i64 t64 = tcg_temp_new_i64(); 1392ad75a51eSRichard Henderson gen_helper_ld_asi(t64, tcg_env, addr, r_asi, r_mop); 1393fcf5ef2aSThomas Huth tcg_gen_trunc_i64_tl(dst, t64); 1394fcf5ef2aSThomas Huth } 1395fcf5ef2aSThomas Huth #endif 1396fcf5ef2aSThomas Huth } 1397fcf5ef2aSThomas Huth break; 1398fcf5ef2aSThomas Huth } 1399fcf5ef2aSThomas Huth } 1400fcf5ef2aSThomas Huth 140142071fc1SRichard Henderson static void gen_st_asi(DisasContext *dc, DisasASI *da, TCGv src, TCGv addr) 1402c03a0fd1SRichard Henderson { 1403c03a0fd1SRichard Henderson switch (da->type) { 1404fcf5ef2aSThomas Huth case GET_ASI_EXCP: 1405fcf5ef2aSThomas Huth break; 1406c03a0fd1SRichard Henderson 1407fcf5ef2aSThomas Huth case GET_ASI_DTWINX: /* Reserved for stda. */ 1408c03a0fd1SRichard Henderson if (TARGET_LONG_BITS == 32) { 1409fcf5ef2aSThomas Huth gen_exception(dc, TT_ILL_INSN); 1410fcf5ef2aSThomas Huth break; 1411c03a0fd1SRichard Henderson } else if (!(dc->def->features & CPU_FEATURE_HYPV)) { 14123390537bSArtyom Tarasenko /* Pre OpenSPARC CPUs don't have these */ 14133390537bSArtyom Tarasenko gen_exception(dc, TT_ILL_INSN); 1414fcf5ef2aSThomas Huth break; 1415c03a0fd1SRichard Henderson } 1416c03a0fd1SRichard Henderson /* In OpenSPARC T1+ CPUs TWINX ASIs in store are ST_BLKINIT_ ASIs */ 1417c03a0fd1SRichard Henderson /* fall through */ 1418c03a0fd1SRichard Henderson 1419c03a0fd1SRichard Henderson case GET_ASI_DIRECT: 1420c03a0fd1SRichard Henderson tcg_gen_qemu_st_tl(src, addr, da->mem_idx, da->memop | MO_ALIGN); 1421c03a0fd1SRichard Henderson break; 1422c03a0fd1SRichard Henderson 1423fcf5ef2aSThomas Huth case GET_ASI_BCOPY: 1424c03a0fd1SRichard Henderson assert(TARGET_LONG_BITS == 32); 142598271007SRichard Henderson /* 142698271007SRichard Henderson * Copy 32 bytes from the address in SRC to ADDR. 142798271007SRichard Henderson * 142898271007SRichard Henderson * From Ross RT625 hyperSPARC manual, section 4.6: 142998271007SRichard Henderson * "Block Copy and Block Fill will work only on cache line boundaries." 143098271007SRichard Henderson * 143198271007SRichard Henderson * It does not specify if an unaliged address is truncated or trapped. 143298271007SRichard Henderson * Previous qemu behaviour was to truncate to 4 byte alignment, which 143398271007SRichard Henderson * is obviously wrong. The only place I can see this used is in the 143498271007SRichard Henderson * Linux kernel which begins with page alignment, advancing by 32, 143598271007SRichard Henderson * so is always aligned. Assume truncation as the simpler option. 143698271007SRichard Henderson * 143798271007SRichard Henderson * Since the loads and stores are paired, allow the copy to happen 143898271007SRichard Henderson * in the host endianness. The copy need not be atomic. 143998271007SRichard Henderson */ 1440fcf5ef2aSThomas Huth { 144198271007SRichard Henderson MemOp mop = MO_128 | MO_ATOM_IFALIGN_PAIR; 1442fcf5ef2aSThomas Huth TCGv saddr = tcg_temp_new(); 1443fcf5ef2aSThomas Huth TCGv daddr = tcg_temp_new(); 144498271007SRichard Henderson TCGv_i128 tmp = tcg_temp_new_i128(); 1445fcf5ef2aSThomas Huth 144698271007SRichard Henderson tcg_gen_andi_tl(saddr, src, -32); 144798271007SRichard Henderson tcg_gen_andi_tl(daddr, addr, -32); 144898271007SRichard Henderson tcg_gen_qemu_ld_i128(tmp, saddr, da->mem_idx, mop); 144998271007SRichard Henderson tcg_gen_qemu_st_i128(tmp, daddr, da->mem_idx, mop); 145098271007SRichard Henderson tcg_gen_addi_tl(saddr, saddr, 16); 145198271007SRichard Henderson tcg_gen_addi_tl(daddr, daddr, 16); 145298271007SRichard Henderson tcg_gen_qemu_ld_i128(tmp, saddr, da->mem_idx, mop); 145398271007SRichard Henderson tcg_gen_qemu_st_i128(tmp, daddr, da->mem_idx, mop); 1454fcf5ef2aSThomas Huth } 1455fcf5ef2aSThomas Huth break; 1456c03a0fd1SRichard Henderson 1457fcf5ef2aSThomas Huth default: 1458fcf5ef2aSThomas Huth { 1459c03a0fd1SRichard Henderson TCGv_i32 r_asi = tcg_constant_i32(da->asi); 1460c03a0fd1SRichard Henderson TCGv_i32 r_mop = tcg_constant_i32(da->memop | MO_ALIGN); 1461fcf5ef2aSThomas Huth 1462fcf5ef2aSThomas Huth save_state(dc); 1463fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 1464ad75a51eSRichard Henderson gen_helper_st_asi(tcg_env, addr, src, r_asi, r_mop); 1465fcf5ef2aSThomas Huth #else 1466fcf5ef2aSThomas Huth { 1467fcf5ef2aSThomas Huth TCGv_i64 t64 = tcg_temp_new_i64(); 1468fcf5ef2aSThomas Huth tcg_gen_extu_tl_i64(t64, src); 1469ad75a51eSRichard Henderson gen_helper_st_asi(tcg_env, addr, t64, r_asi, r_mop); 1470fcf5ef2aSThomas Huth } 1471fcf5ef2aSThomas Huth #endif 1472fcf5ef2aSThomas Huth 1473fcf5ef2aSThomas Huth /* A write to a TLB register may alter page maps. End the TB. */ 1474fcf5ef2aSThomas Huth dc->npc = DYNAMIC_PC; 1475fcf5ef2aSThomas Huth } 1476fcf5ef2aSThomas Huth break; 1477fcf5ef2aSThomas Huth } 1478fcf5ef2aSThomas Huth } 1479fcf5ef2aSThomas Huth 1480dca544b9SRichard Henderson static void gen_swap_asi(DisasContext *dc, DisasASI *da, 1481c03a0fd1SRichard Henderson TCGv dst, TCGv src, TCGv addr) 1482c03a0fd1SRichard Henderson { 1483c03a0fd1SRichard Henderson switch (da->type) { 1484c03a0fd1SRichard Henderson case GET_ASI_EXCP: 1485c03a0fd1SRichard Henderson break; 1486c03a0fd1SRichard Henderson case GET_ASI_DIRECT: 1487dca544b9SRichard Henderson tcg_gen_atomic_xchg_tl(dst, addr, src, 1488dca544b9SRichard Henderson da->mem_idx, da->memop | MO_ALIGN); 1489c03a0fd1SRichard Henderson break; 1490c03a0fd1SRichard Henderson default: 1491c03a0fd1SRichard Henderson /* ??? Should be DAE_invalid_asi. */ 1492c03a0fd1SRichard Henderson gen_exception(dc, TT_DATA_ACCESS); 1493c03a0fd1SRichard Henderson break; 1494c03a0fd1SRichard Henderson } 1495c03a0fd1SRichard Henderson } 1496c03a0fd1SRichard Henderson 1497d0a11d25SRichard Henderson static void gen_cas_asi(DisasContext *dc, DisasASI *da, 1498c03a0fd1SRichard Henderson TCGv oldv, TCGv newv, TCGv cmpv, TCGv addr) 1499c03a0fd1SRichard Henderson { 1500c03a0fd1SRichard Henderson switch (da->type) { 1501fcf5ef2aSThomas Huth case GET_ASI_EXCP: 1502c03a0fd1SRichard Henderson return; 1503fcf5ef2aSThomas Huth case GET_ASI_DIRECT: 1504c03a0fd1SRichard Henderson tcg_gen_atomic_cmpxchg_tl(oldv, addr, cmpv, newv, 1505c03a0fd1SRichard Henderson da->mem_idx, da->memop | MO_ALIGN); 1506fcf5ef2aSThomas Huth break; 1507fcf5ef2aSThomas Huth default: 1508fcf5ef2aSThomas Huth /* ??? Should be DAE_invalid_asi. */ 1509fcf5ef2aSThomas Huth gen_exception(dc, TT_DATA_ACCESS); 1510fcf5ef2aSThomas Huth break; 1511fcf5ef2aSThomas Huth } 1512fcf5ef2aSThomas Huth } 1513fcf5ef2aSThomas Huth 1514cf07cd1eSRichard Henderson static void gen_ldstub_asi(DisasContext *dc, DisasASI *da, TCGv dst, TCGv addr) 1515c03a0fd1SRichard Henderson { 1516c03a0fd1SRichard Henderson switch (da->type) { 1517fcf5ef2aSThomas Huth case GET_ASI_EXCP: 1518fcf5ef2aSThomas Huth break; 1519fcf5ef2aSThomas Huth case GET_ASI_DIRECT: 1520cf07cd1eSRichard Henderson tcg_gen_atomic_xchg_tl(dst, addr, tcg_constant_tl(0xff), 1521cf07cd1eSRichard Henderson da->mem_idx, MO_UB); 1522fcf5ef2aSThomas Huth break; 1523fcf5ef2aSThomas Huth default: 15243db010c3SRichard Henderson /* ??? In theory, this should be raise DAE_invalid_asi. 15253db010c3SRichard Henderson But the SS-20 roms do ldstuba [%l0] #ASI_M_CTL, %o1. */ 1526af00be49SEmilio G. Cota if (tb_cflags(dc->base.tb) & CF_PARALLEL) { 1527ad75a51eSRichard Henderson gen_helper_exit_atomic(tcg_env); 15283db010c3SRichard Henderson } else { 1529c03a0fd1SRichard Henderson TCGv_i32 r_asi = tcg_constant_i32(da->asi); 153000ab7e61SRichard Henderson TCGv_i32 r_mop = tcg_constant_i32(MO_UB); 15313db010c3SRichard Henderson TCGv_i64 s64, t64; 15323db010c3SRichard Henderson 15333db010c3SRichard Henderson save_state(dc); 15343db010c3SRichard Henderson t64 = tcg_temp_new_i64(); 1535ad75a51eSRichard Henderson gen_helper_ld_asi(t64, tcg_env, addr, r_asi, r_mop); 15363db010c3SRichard Henderson 153700ab7e61SRichard Henderson s64 = tcg_constant_i64(0xff); 1538ad75a51eSRichard Henderson gen_helper_st_asi(tcg_env, addr, s64, r_asi, r_mop); 15393db010c3SRichard Henderson 15403db010c3SRichard Henderson tcg_gen_trunc_i64_tl(dst, t64); 15413db010c3SRichard Henderson 15423db010c3SRichard Henderson /* End the TB. */ 15433db010c3SRichard Henderson dc->npc = DYNAMIC_PC; 15443db010c3SRichard Henderson } 1545fcf5ef2aSThomas Huth break; 1546fcf5ef2aSThomas Huth } 1547fcf5ef2aSThomas Huth } 1548fcf5ef2aSThomas Huth 1549287b1152SRichard Henderson static void gen_ldf_asi(DisasContext *dc, DisasASI *da, MemOp orig_size, 15503259b9e2SRichard Henderson TCGv addr, int rd) 1551fcf5ef2aSThomas Huth { 15523259b9e2SRichard Henderson MemOp memop = da->memop; 15533259b9e2SRichard Henderson MemOp size = memop & MO_SIZE; 1554fcf5ef2aSThomas Huth TCGv_i32 d32; 1555fcf5ef2aSThomas Huth TCGv_i64 d64; 1556287b1152SRichard Henderson TCGv addr_tmp; 1557fcf5ef2aSThomas Huth 15583259b9e2SRichard Henderson /* TODO: Use 128-bit load/store below. */ 15593259b9e2SRichard Henderson if (size == MO_128) { 15603259b9e2SRichard Henderson memop = (memop & ~MO_SIZE) | MO_64; 15613259b9e2SRichard Henderson } 15623259b9e2SRichard Henderson 15633259b9e2SRichard Henderson switch (da->type) { 1564fcf5ef2aSThomas Huth case GET_ASI_EXCP: 1565fcf5ef2aSThomas Huth break; 1566fcf5ef2aSThomas Huth 1567fcf5ef2aSThomas Huth case GET_ASI_DIRECT: 15683259b9e2SRichard Henderson memop |= MO_ALIGN_4; 1569fcf5ef2aSThomas Huth switch (size) { 15703259b9e2SRichard Henderson case MO_32: 1571388a6465SRichard Henderson d32 = tcg_temp_new_i32(); 15723259b9e2SRichard Henderson tcg_gen_qemu_ld_i32(d32, addr, da->mem_idx, memop); 1573fcf5ef2aSThomas Huth gen_store_fpr_F(dc, rd, d32); 1574fcf5ef2aSThomas Huth break; 15753259b9e2SRichard Henderson 15763259b9e2SRichard Henderson case MO_64: 15773259b9e2SRichard Henderson tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da->mem_idx, memop); 1578fcf5ef2aSThomas Huth break; 15793259b9e2SRichard Henderson 15803259b9e2SRichard Henderson case MO_128: 1581fcf5ef2aSThomas Huth d64 = tcg_temp_new_i64(); 15823259b9e2SRichard Henderson tcg_gen_qemu_ld_i64(d64, addr, da->mem_idx, memop); 1583287b1152SRichard Henderson addr_tmp = tcg_temp_new(); 1584287b1152SRichard Henderson tcg_gen_addi_tl(addr_tmp, addr, 8); 1585287b1152SRichard Henderson tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + 1], addr_tmp, da->mem_idx, memop); 1586fcf5ef2aSThomas Huth tcg_gen_mov_i64(cpu_fpr[rd / 2], d64); 1587fcf5ef2aSThomas Huth break; 1588fcf5ef2aSThomas Huth default: 1589fcf5ef2aSThomas Huth g_assert_not_reached(); 1590fcf5ef2aSThomas Huth } 1591fcf5ef2aSThomas Huth break; 1592fcf5ef2aSThomas Huth 1593fcf5ef2aSThomas Huth case GET_ASI_BLOCK: 1594fcf5ef2aSThomas Huth /* Valid for lddfa on aligned registers only. */ 15953259b9e2SRichard Henderson if (orig_size == MO_64 && (rd & 7) == 0) { 1596fcf5ef2aSThomas Huth /* The first operation checks required alignment. */ 1597287b1152SRichard Henderson addr_tmp = tcg_temp_new(); 1598287b1152SRichard Henderson for (int i = 0; ; ++i) { 15993259b9e2SRichard Henderson tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2 + i], addr, da->mem_idx, 16003259b9e2SRichard Henderson memop | (i == 0 ? MO_ALIGN_64 : 0)); 1601fcf5ef2aSThomas Huth if (i == 7) { 1602fcf5ef2aSThomas Huth break; 1603fcf5ef2aSThomas Huth } 1604287b1152SRichard Henderson tcg_gen_addi_tl(addr_tmp, addr, 8); 1605287b1152SRichard Henderson addr = addr_tmp; 1606fcf5ef2aSThomas Huth } 1607fcf5ef2aSThomas Huth } else { 1608fcf5ef2aSThomas Huth gen_exception(dc, TT_ILL_INSN); 1609fcf5ef2aSThomas Huth } 1610fcf5ef2aSThomas Huth break; 1611fcf5ef2aSThomas Huth 1612fcf5ef2aSThomas Huth case GET_ASI_SHORT: 1613fcf5ef2aSThomas Huth /* Valid for lddfa only. */ 16143259b9e2SRichard Henderson if (orig_size == MO_64) { 16153259b9e2SRichard Henderson tcg_gen_qemu_ld_i64(cpu_fpr[rd / 2], addr, da->mem_idx, 16163259b9e2SRichard Henderson memop | MO_ALIGN); 1617fcf5ef2aSThomas Huth } else { 1618fcf5ef2aSThomas Huth gen_exception(dc, TT_ILL_INSN); 1619fcf5ef2aSThomas Huth } 1620fcf5ef2aSThomas Huth break; 1621fcf5ef2aSThomas Huth 1622fcf5ef2aSThomas Huth default: 1623fcf5ef2aSThomas Huth { 16243259b9e2SRichard Henderson TCGv_i32 r_asi = tcg_constant_i32(da->asi); 16253259b9e2SRichard Henderson TCGv_i32 r_mop = tcg_constant_i32(memop | MO_ALIGN); 1626fcf5ef2aSThomas Huth 1627fcf5ef2aSThomas Huth save_state(dc); 1628fcf5ef2aSThomas Huth /* According to the table in the UA2011 manual, the only 1629fcf5ef2aSThomas Huth other asis that are valid for ldfa/lddfa/ldqfa are 1630fcf5ef2aSThomas Huth the NO_FAULT asis. We still need a helper for these, 1631fcf5ef2aSThomas Huth but we can just use the integer asi helper for them. */ 1632fcf5ef2aSThomas Huth switch (size) { 16333259b9e2SRichard Henderson case MO_32: 1634fcf5ef2aSThomas Huth d64 = tcg_temp_new_i64(); 1635ad75a51eSRichard Henderson gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop); 1636388a6465SRichard Henderson d32 = tcg_temp_new_i32(); 1637fcf5ef2aSThomas Huth tcg_gen_extrl_i64_i32(d32, d64); 1638fcf5ef2aSThomas Huth gen_store_fpr_F(dc, rd, d32); 1639fcf5ef2aSThomas Huth break; 16403259b9e2SRichard Henderson case MO_64: 16413259b9e2SRichard Henderson gen_helper_ld_asi(cpu_fpr[rd / 2], tcg_env, addr, 16423259b9e2SRichard Henderson r_asi, r_mop); 1643fcf5ef2aSThomas Huth break; 16443259b9e2SRichard Henderson case MO_128: 1645fcf5ef2aSThomas Huth d64 = tcg_temp_new_i64(); 1646ad75a51eSRichard Henderson gen_helper_ld_asi(d64, tcg_env, addr, r_asi, r_mop); 1647287b1152SRichard Henderson addr_tmp = tcg_temp_new(); 1648287b1152SRichard Henderson tcg_gen_addi_tl(addr_tmp, addr, 8); 1649287b1152SRichard Henderson gen_helper_ld_asi(cpu_fpr[rd / 2 + 1], tcg_env, addr_tmp, 16503259b9e2SRichard Henderson r_asi, r_mop); 1651fcf5ef2aSThomas Huth tcg_gen_mov_i64(cpu_fpr[rd / 2], d64); 1652fcf5ef2aSThomas Huth break; 1653fcf5ef2aSThomas Huth default: 1654fcf5ef2aSThomas Huth g_assert_not_reached(); 1655fcf5ef2aSThomas Huth } 1656fcf5ef2aSThomas Huth } 1657fcf5ef2aSThomas Huth break; 1658fcf5ef2aSThomas Huth } 1659fcf5ef2aSThomas Huth } 1660fcf5ef2aSThomas Huth 1661287b1152SRichard Henderson static void gen_stf_asi(DisasContext *dc, DisasASI *da, MemOp orig_size, 16623259b9e2SRichard Henderson TCGv addr, int rd) 16633259b9e2SRichard Henderson { 16643259b9e2SRichard Henderson MemOp memop = da->memop; 16653259b9e2SRichard Henderson MemOp size = memop & MO_SIZE; 1666fcf5ef2aSThomas Huth TCGv_i32 d32; 1667287b1152SRichard Henderson TCGv addr_tmp; 1668fcf5ef2aSThomas Huth 16693259b9e2SRichard Henderson /* TODO: Use 128-bit load/store below. */ 16703259b9e2SRichard Henderson if (size == MO_128) { 16713259b9e2SRichard Henderson memop = (memop & ~MO_SIZE) | MO_64; 16723259b9e2SRichard Henderson } 16733259b9e2SRichard Henderson 16743259b9e2SRichard Henderson switch (da->type) { 1675fcf5ef2aSThomas Huth case GET_ASI_EXCP: 1676fcf5ef2aSThomas Huth break; 1677fcf5ef2aSThomas Huth 1678fcf5ef2aSThomas Huth case GET_ASI_DIRECT: 16793259b9e2SRichard Henderson memop |= MO_ALIGN_4; 1680fcf5ef2aSThomas Huth switch (size) { 16813259b9e2SRichard Henderson case MO_32: 1682fcf5ef2aSThomas Huth d32 = gen_load_fpr_F(dc, rd); 16833259b9e2SRichard Henderson tcg_gen_qemu_st_i32(d32, addr, da->mem_idx, memop | MO_ALIGN); 1684fcf5ef2aSThomas Huth break; 16853259b9e2SRichard Henderson case MO_64: 16863259b9e2SRichard Henderson tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx, 16873259b9e2SRichard Henderson memop | MO_ALIGN_4); 1688fcf5ef2aSThomas Huth break; 16893259b9e2SRichard Henderson case MO_128: 1690fcf5ef2aSThomas Huth /* Only 4-byte alignment required. However, it is legal for the 1691fcf5ef2aSThomas Huth cpu to signal the alignment fault, and the OS trap handler is 1692fcf5ef2aSThomas Huth required to fix it up. Requiring 16-byte alignment here avoids 1693fcf5ef2aSThomas Huth having to probe the second page before performing the first 1694fcf5ef2aSThomas Huth write. */ 16953259b9e2SRichard Henderson tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx, 16963259b9e2SRichard Henderson memop | MO_ALIGN_16); 1697287b1152SRichard Henderson addr_tmp = tcg_temp_new(); 1698287b1152SRichard Henderson tcg_gen_addi_tl(addr_tmp, addr, 8); 1699287b1152SRichard Henderson tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + 1], addr_tmp, da->mem_idx, memop); 1700fcf5ef2aSThomas Huth break; 1701fcf5ef2aSThomas Huth default: 1702fcf5ef2aSThomas Huth g_assert_not_reached(); 1703fcf5ef2aSThomas Huth } 1704fcf5ef2aSThomas Huth break; 1705fcf5ef2aSThomas Huth 1706fcf5ef2aSThomas Huth case GET_ASI_BLOCK: 1707fcf5ef2aSThomas Huth /* Valid for stdfa on aligned registers only. */ 17083259b9e2SRichard Henderson if (orig_size == MO_64 && (rd & 7) == 0) { 1709fcf5ef2aSThomas Huth /* The first operation checks required alignment. */ 1710287b1152SRichard Henderson addr_tmp = tcg_temp_new(); 1711287b1152SRichard Henderson for (int i = 0; ; ++i) { 17123259b9e2SRichard Henderson tcg_gen_qemu_st_i64(cpu_fpr[rd / 2 + i], addr, da->mem_idx, 17133259b9e2SRichard Henderson memop | (i == 0 ? MO_ALIGN_64 : 0)); 1714fcf5ef2aSThomas Huth if (i == 7) { 1715fcf5ef2aSThomas Huth break; 1716fcf5ef2aSThomas Huth } 1717287b1152SRichard Henderson tcg_gen_addi_tl(addr_tmp, addr, 8); 1718287b1152SRichard Henderson addr = addr_tmp; 1719fcf5ef2aSThomas Huth } 1720fcf5ef2aSThomas Huth } else { 1721fcf5ef2aSThomas Huth gen_exception(dc, TT_ILL_INSN); 1722fcf5ef2aSThomas Huth } 1723fcf5ef2aSThomas Huth break; 1724fcf5ef2aSThomas Huth 1725fcf5ef2aSThomas Huth case GET_ASI_SHORT: 1726fcf5ef2aSThomas Huth /* Valid for stdfa only. */ 17273259b9e2SRichard Henderson if (orig_size == MO_64) { 17283259b9e2SRichard Henderson tcg_gen_qemu_st_i64(cpu_fpr[rd / 2], addr, da->mem_idx, 17293259b9e2SRichard Henderson memop | MO_ALIGN); 1730fcf5ef2aSThomas Huth } else { 1731fcf5ef2aSThomas Huth gen_exception(dc, TT_ILL_INSN); 1732fcf5ef2aSThomas Huth } 1733fcf5ef2aSThomas Huth break; 1734fcf5ef2aSThomas Huth 1735fcf5ef2aSThomas Huth default: 1736fcf5ef2aSThomas Huth /* According to the table in the UA2011 manual, the only 1737fcf5ef2aSThomas Huth other asis that are valid for ldfa/lddfa/ldqfa are 1738fcf5ef2aSThomas Huth the PST* asis, which aren't currently handled. */ 1739fcf5ef2aSThomas Huth gen_exception(dc, TT_ILL_INSN); 1740fcf5ef2aSThomas Huth break; 1741fcf5ef2aSThomas Huth } 1742fcf5ef2aSThomas Huth } 1743fcf5ef2aSThomas Huth 174442071fc1SRichard Henderson static void gen_ldda_asi(DisasContext *dc, DisasASI *da, TCGv addr, int rd) 1745fcf5ef2aSThomas Huth { 1746a76779eeSRichard Henderson TCGv hi = gen_dest_gpr(dc, rd); 1747a76779eeSRichard Henderson TCGv lo = gen_dest_gpr(dc, rd + 1); 1748fcf5ef2aSThomas Huth 1749c03a0fd1SRichard Henderson switch (da->type) { 1750fcf5ef2aSThomas Huth case GET_ASI_EXCP: 1751fcf5ef2aSThomas Huth return; 1752fcf5ef2aSThomas Huth 1753fcf5ef2aSThomas Huth case GET_ASI_DTWINX: 1754ebbbec92SRichard Henderson #ifdef TARGET_SPARC64 1755ebbbec92SRichard Henderson { 1756ebbbec92SRichard Henderson MemOp mop = (da->memop & MO_BSWAP) | MO_128 | MO_ALIGN_16; 1757ebbbec92SRichard Henderson TCGv_i128 t = tcg_temp_new_i128(); 1758ebbbec92SRichard Henderson 1759ebbbec92SRichard Henderson tcg_gen_qemu_ld_i128(t, addr, da->mem_idx, mop); 1760ebbbec92SRichard Henderson /* 1761ebbbec92SRichard Henderson * Note that LE twinx acts as if each 64-bit register result is 1762ebbbec92SRichard Henderson * byte swapped. We perform one 128-bit LE load, so must swap 1763ebbbec92SRichard Henderson * the order of the writebacks. 1764ebbbec92SRichard Henderson */ 1765ebbbec92SRichard Henderson if ((mop & MO_BSWAP) == MO_TE) { 1766ebbbec92SRichard Henderson tcg_gen_extr_i128_i64(lo, hi, t); 1767ebbbec92SRichard Henderson } else { 1768ebbbec92SRichard Henderson tcg_gen_extr_i128_i64(hi, lo, t); 1769ebbbec92SRichard Henderson } 1770ebbbec92SRichard Henderson } 1771fcf5ef2aSThomas Huth break; 1772ebbbec92SRichard Henderson #else 1773ebbbec92SRichard Henderson g_assert_not_reached(); 1774ebbbec92SRichard Henderson #endif 1775fcf5ef2aSThomas Huth 1776fcf5ef2aSThomas Huth case GET_ASI_DIRECT: 1777fcf5ef2aSThomas Huth { 1778fcf5ef2aSThomas Huth TCGv_i64 tmp = tcg_temp_new_i64(); 1779fcf5ef2aSThomas Huth 1780c03a0fd1SRichard Henderson tcg_gen_qemu_ld_i64(tmp, addr, da->mem_idx, da->memop | MO_ALIGN); 1781fcf5ef2aSThomas Huth 1782fcf5ef2aSThomas Huth /* Note that LE ldda acts as if each 32-bit register 1783fcf5ef2aSThomas Huth result is byte swapped. Having just performed one 1784fcf5ef2aSThomas Huth 64-bit bswap, we need now to swap the writebacks. */ 1785c03a0fd1SRichard Henderson if ((da->memop & MO_BSWAP) == MO_TE) { 1786a76779eeSRichard Henderson tcg_gen_extr_i64_tl(lo, hi, tmp); 1787fcf5ef2aSThomas Huth } else { 1788a76779eeSRichard Henderson tcg_gen_extr_i64_tl(hi, lo, tmp); 1789fcf5ef2aSThomas Huth } 1790fcf5ef2aSThomas Huth } 1791fcf5ef2aSThomas Huth break; 1792fcf5ef2aSThomas Huth 1793fcf5ef2aSThomas Huth default: 1794fcf5ef2aSThomas Huth /* ??? In theory we've handled all of the ASIs that are valid 1795fcf5ef2aSThomas Huth for ldda, and this should raise DAE_invalid_asi. However, 1796fcf5ef2aSThomas Huth real hardware allows others. This can be seen with e.g. 1797fcf5ef2aSThomas Huth FreeBSD 10.3 wrt ASI_IC_TAG. */ 1798fcf5ef2aSThomas Huth { 1799c03a0fd1SRichard Henderson TCGv_i32 r_asi = tcg_constant_i32(da->asi); 1800c03a0fd1SRichard Henderson TCGv_i32 r_mop = tcg_constant_i32(da->memop); 1801fcf5ef2aSThomas Huth TCGv_i64 tmp = tcg_temp_new_i64(); 1802fcf5ef2aSThomas Huth 1803fcf5ef2aSThomas Huth save_state(dc); 1804ad75a51eSRichard Henderson gen_helper_ld_asi(tmp, tcg_env, addr, r_asi, r_mop); 1805fcf5ef2aSThomas Huth 1806fcf5ef2aSThomas Huth /* See above. */ 1807c03a0fd1SRichard Henderson if ((da->memop & MO_BSWAP) == MO_TE) { 1808a76779eeSRichard Henderson tcg_gen_extr_i64_tl(lo, hi, tmp); 1809fcf5ef2aSThomas Huth } else { 1810a76779eeSRichard Henderson tcg_gen_extr_i64_tl(hi, lo, tmp); 1811fcf5ef2aSThomas Huth } 1812fcf5ef2aSThomas Huth } 1813fcf5ef2aSThomas Huth break; 1814fcf5ef2aSThomas Huth } 1815fcf5ef2aSThomas Huth 1816fcf5ef2aSThomas Huth gen_store_gpr(dc, rd, hi); 1817fcf5ef2aSThomas Huth gen_store_gpr(dc, rd + 1, lo); 1818fcf5ef2aSThomas Huth } 1819fcf5ef2aSThomas Huth 182042071fc1SRichard Henderson static void gen_stda_asi(DisasContext *dc, DisasASI *da, TCGv addr, int rd) 1821c03a0fd1SRichard Henderson { 1822c03a0fd1SRichard Henderson TCGv hi = gen_load_gpr(dc, rd); 1823fcf5ef2aSThomas Huth TCGv lo = gen_load_gpr(dc, rd + 1); 1824fcf5ef2aSThomas Huth 1825c03a0fd1SRichard Henderson switch (da->type) { 1826fcf5ef2aSThomas Huth case GET_ASI_EXCP: 1827fcf5ef2aSThomas Huth break; 1828fcf5ef2aSThomas Huth 1829fcf5ef2aSThomas Huth case GET_ASI_DTWINX: 1830ebbbec92SRichard Henderson #ifdef TARGET_SPARC64 1831ebbbec92SRichard Henderson { 1832ebbbec92SRichard Henderson MemOp mop = (da->memop & MO_BSWAP) | MO_128 | MO_ALIGN_16; 1833ebbbec92SRichard Henderson TCGv_i128 t = tcg_temp_new_i128(); 1834ebbbec92SRichard Henderson 1835ebbbec92SRichard Henderson /* 1836ebbbec92SRichard Henderson * Note that LE twinx acts as if each 64-bit register result is 1837ebbbec92SRichard Henderson * byte swapped. We perform one 128-bit LE store, so must swap 1838ebbbec92SRichard Henderson * the order of the construction. 1839ebbbec92SRichard Henderson */ 1840ebbbec92SRichard Henderson if ((mop & MO_BSWAP) == MO_TE) { 1841ebbbec92SRichard Henderson tcg_gen_concat_i64_i128(t, lo, hi); 1842ebbbec92SRichard Henderson } else { 1843ebbbec92SRichard Henderson tcg_gen_concat_i64_i128(t, hi, lo); 1844ebbbec92SRichard Henderson } 1845ebbbec92SRichard Henderson tcg_gen_qemu_st_i128(t, addr, da->mem_idx, mop); 1846ebbbec92SRichard Henderson } 1847fcf5ef2aSThomas Huth break; 1848ebbbec92SRichard Henderson #else 1849ebbbec92SRichard Henderson g_assert_not_reached(); 1850ebbbec92SRichard Henderson #endif 1851fcf5ef2aSThomas Huth 1852fcf5ef2aSThomas Huth case GET_ASI_DIRECT: 1853fcf5ef2aSThomas Huth { 1854fcf5ef2aSThomas Huth TCGv_i64 t64 = tcg_temp_new_i64(); 1855fcf5ef2aSThomas Huth 1856fcf5ef2aSThomas Huth /* Note that LE stda acts as if each 32-bit register result is 1857fcf5ef2aSThomas Huth byte swapped. We will perform one 64-bit LE store, so now 1858fcf5ef2aSThomas Huth we must swap the order of the construction. */ 1859c03a0fd1SRichard Henderson if ((da->memop & MO_BSWAP) == MO_TE) { 1860a76779eeSRichard Henderson tcg_gen_concat_tl_i64(t64, lo, hi); 1861fcf5ef2aSThomas Huth } else { 1862a76779eeSRichard Henderson tcg_gen_concat_tl_i64(t64, hi, lo); 1863fcf5ef2aSThomas Huth } 1864c03a0fd1SRichard Henderson tcg_gen_qemu_st_i64(t64, addr, da->mem_idx, da->memop | MO_ALIGN); 1865fcf5ef2aSThomas Huth } 1866fcf5ef2aSThomas Huth break; 1867fcf5ef2aSThomas Huth 1868a76779eeSRichard Henderson case GET_ASI_BFILL: 1869a76779eeSRichard Henderson assert(TARGET_LONG_BITS == 32); 187054c3e953SRichard Henderson /* 187154c3e953SRichard Henderson * Store 32 bytes of [rd:rd+1] to ADDR. 187254c3e953SRichard Henderson * See comments for GET_ASI_COPY above. 187354c3e953SRichard Henderson */ 1874a76779eeSRichard Henderson { 187554c3e953SRichard Henderson MemOp mop = MO_TE | MO_128 | MO_ATOM_IFALIGN_PAIR; 187654c3e953SRichard Henderson TCGv_i64 t8 = tcg_temp_new_i64(); 187754c3e953SRichard Henderson TCGv_i128 t16 = tcg_temp_new_i128(); 187854c3e953SRichard Henderson TCGv daddr = tcg_temp_new(); 1879a76779eeSRichard Henderson 188054c3e953SRichard Henderson tcg_gen_concat_tl_i64(t8, lo, hi); 188154c3e953SRichard Henderson tcg_gen_concat_i64_i128(t16, t8, t8); 188254c3e953SRichard Henderson tcg_gen_andi_tl(daddr, addr, -32); 188354c3e953SRichard Henderson tcg_gen_qemu_st_i128(t16, daddr, da->mem_idx, mop); 188454c3e953SRichard Henderson tcg_gen_addi_tl(daddr, daddr, 16); 188554c3e953SRichard Henderson tcg_gen_qemu_st_i128(t16, daddr, da->mem_idx, mop); 1886a76779eeSRichard Henderson } 1887a76779eeSRichard Henderson break; 1888a76779eeSRichard Henderson 1889fcf5ef2aSThomas Huth default: 1890fcf5ef2aSThomas Huth /* ??? In theory we've handled all of the ASIs that are valid 1891fcf5ef2aSThomas Huth for stda, and this should raise DAE_invalid_asi. */ 1892fcf5ef2aSThomas Huth { 1893c03a0fd1SRichard Henderson TCGv_i32 r_asi = tcg_constant_i32(da->asi); 1894c03a0fd1SRichard Henderson TCGv_i32 r_mop = tcg_constant_i32(da->memop); 1895fcf5ef2aSThomas Huth TCGv_i64 t64 = tcg_temp_new_i64(); 1896fcf5ef2aSThomas Huth 1897fcf5ef2aSThomas Huth /* See above. */ 1898c03a0fd1SRichard Henderson if ((da->memop & MO_BSWAP) == MO_TE) { 1899a76779eeSRichard Henderson tcg_gen_concat_tl_i64(t64, lo, hi); 1900fcf5ef2aSThomas Huth } else { 1901a76779eeSRichard Henderson tcg_gen_concat_tl_i64(t64, hi, lo); 1902fcf5ef2aSThomas Huth } 1903fcf5ef2aSThomas Huth 1904fcf5ef2aSThomas Huth save_state(dc); 1905ad75a51eSRichard Henderson gen_helper_st_asi(tcg_env, addr, t64, r_asi, r_mop); 1906fcf5ef2aSThomas Huth } 1907fcf5ef2aSThomas Huth break; 1908fcf5ef2aSThomas Huth } 1909fcf5ef2aSThomas Huth } 1910fcf5ef2aSThomas Huth 1911fcf5ef2aSThomas Huth static void gen_fmovs(DisasContext *dc, DisasCompare *cmp, int rd, int rs) 1912fcf5ef2aSThomas Huth { 1913f7ec8155SRichard Henderson #ifdef TARGET_SPARC64 1914fcf5ef2aSThomas Huth TCGv_i32 c32, zero, dst, s1, s2; 1915dd7dbfccSRichard Henderson TCGv_i64 c64 = tcg_temp_new_i64(); 1916fcf5ef2aSThomas Huth 1917fcf5ef2aSThomas Huth /* We have two choices here: extend the 32 bit data and use movcond_i64, 1918fcf5ef2aSThomas Huth or fold the comparison down to 32 bits and use movcond_i32. Choose 1919fcf5ef2aSThomas Huth the later. */ 1920fcf5ef2aSThomas Huth c32 = tcg_temp_new_i32(); 1921c8507ebfSRichard Henderson tcg_gen_setcondi_i64(cmp->cond, c64, cmp->c1, cmp->c2); 1922fcf5ef2aSThomas Huth tcg_gen_extrl_i64_i32(c32, c64); 1923fcf5ef2aSThomas Huth 1924fcf5ef2aSThomas Huth s1 = gen_load_fpr_F(dc, rs); 1925fcf5ef2aSThomas Huth s2 = gen_load_fpr_F(dc, rd); 1926388a6465SRichard Henderson dst = tcg_temp_new_i32(); 192700ab7e61SRichard Henderson zero = tcg_constant_i32(0); 1928fcf5ef2aSThomas Huth 1929fcf5ef2aSThomas Huth tcg_gen_movcond_i32(TCG_COND_NE, dst, c32, zero, s1, s2); 1930fcf5ef2aSThomas Huth 1931fcf5ef2aSThomas Huth gen_store_fpr_F(dc, rd, dst); 1932f7ec8155SRichard Henderson #else 1933f7ec8155SRichard Henderson qemu_build_not_reached(); 1934f7ec8155SRichard Henderson #endif 1935fcf5ef2aSThomas Huth } 1936fcf5ef2aSThomas Huth 1937fcf5ef2aSThomas Huth static void gen_fmovd(DisasContext *dc, DisasCompare *cmp, int rd, int rs) 1938fcf5ef2aSThomas Huth { 1939f7ec8155SRichard Henderson #ifdef TARGET_SPARC64 1940fcf5ef2aSThomas Huth TCGv_i64 dst = gen_dest_fpr_D(dc, rd); 1941c8507ebfSRichard Henderson tcg_gen_movcond_i64(cmp->cond, dst, cmp->c1, tcg_constant_tl(cmp->c2), 1942fcf5ef2aSThomas Huth gen_load_fpr_D(dc, rs), 1943fcf5ef2aSThomas Huth gen_load_fpr_D(dc, rd)); 1944fcf5ef2aSThomas Huth gen_store_fpr_D(dc, rd, dst); 1945f7ec8155SRichard Henderson #else 1946f7ec8155SRichard Henderson qemu_build_not_reached(); 1947f7ec8155SRichard Henderson #endif 1948fcf5ef2aSThomas Huth } 1949fcf5ef2aSThomas Huth 1950fcf5ef2aSThomas Huth static void gen_fmovq(DisasContext *dc, DisasCompare *cmp, int rd, int rs) 1951fcf5ef2aSThomas Huth { 1952f7ec8155SRichard Henderson #ifdef TARGET_SPARC64 1953fcf5ef2aSThomas Huth int qd = QFPREG(rd); 1954fcf5ef2aSThomas Huth int qs = QFPREG(rs); 1955c8507ebfSRichard Henderson TCGv c2 = tcg_constant_tl(cmp->c2); 1956fcf5ef2aSThomas Huth 1957c8507ebfSRichard Henderson tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2], cmp->c1, c2, 1958fcf5ef2aSThomas Huth cpu_fpr[qs / 2], cpu_fpr[qd / 2]); 1959c8507ebfSRichard Henderson tcg_gen_movcond_i64(cmp->cond, cpu_fpr[qd / 2 + 1], cmp->c1, c2, 1960fcf5ef2aSThomas Huth cpu_fpr[qs / 2 + 1], cpu_fpr[qd / 2 + 1]); 1961fcf5ef2aSThomas Huth 1962fcf5ef2aSThomas Huth gen_update_fprs_dirty(dc, qd); 1963f7ec8155SRichard Henderson #else 1964f7ec8155SRichard Henderson qemu_build_not_reached(); 1965f7ec8155SRichard Henderson #endif 1966fcf5ef2aSThomas Huth } 1967fcf5ef2aSThomas Huth 1968f7ec8155SRichard Henderson #ifdef TARGET_SPARC64 19695d617bfbSRichard Henderson static void gen_load_trap_state_at_tl(TCGv_ptr r_tsptr) 1970fcf5ef2aSThomas Huth { 1971fcf5ef2aSThomas Huth TCGv_i32 r_tl = tcg_temp_new_i32(); 1972fcf5ef2aSThomas Huth 1973fcf5ef2aSThomas Huth /* load env->tl into r_tl */ 1974ad75a51eSRichard Henderson tcg_gen_ld_i32(r_tl, tcg_env, offsetof(CPUSPARCState, tl)); 1975fcf5ef2aSThomas Huth 1976fcf5ef2aSThomas Huth /* tl = [0 ... MAXTL_MASK] where MAXTL_MASK must be power of 2 */ 1977fcf5ef2aSThomas Huth tcg_gen_andi_i32(r_tl, r_tl, MAXTL_MASK); 1978fcf5ef2aSThomas Huth 1979fcf5ef2aSThomas Huth /* calculate offset to current trap state from env->ts, reuse r_tl */ 1980fcf5ef2aSThomas Huth tcg_gen_muli_i32(r_tl, r_tl, sizeof (trap_state)); 1981ad75a51eSRichard Henderson tcg_gen_addi_ptr(r_tsptr, tcg_env, offsetof(CPUSPARCState, ts)); 1982fcf5ef2aSThomas Huth 1983fcf5ef2aSThomas Huth /* tsptr = env->ts[env->tl & MAXTL_MASK] */ 1984fcf5ef2aSThomas Huth { 1985fcf5ef2aSThomas Huth TCGv_ptr r_tl_tmp = tcg_temp_new_ptr(); 1986fcf5ef2aSThomas Huth tcg_gen_ext_i32_ptr(r_tl_tmp, r_tl); 1987fcf5ef2aSThomas Huth tcg_gen_add_ptr(r_tsptr, r_tsptr, r_tl_tmp); 1988fcf5ef2aSThomas Huth } 1989fcf5ef2aSThomas Huth } 1990fcf5ef2aSThomas Huth #endif 1991fcf5ef2aSThomas Huth 199206c060d9SRichard Henderson static int extract_dfpreg(DisasContext *dc, int x) 199306c060d9SRichard Henderson { 199406c060d9SRichard Henderson return DFPREG(x); 199506c060d9SRichard Henderson } 199606c060d9SRichard Henderson 199706c060d9SRichard Henderson static int extract_qfpreg(DisasContext *dc, int x) 199806c060d9SRichard Henderson { 199906c060d9SRichard Henderson return QFPREG(x); 200006c060d9SRichard Henderson } 200106c060d9SRichard Henderson 2002878cc677SRichard Henderson /* Include the auto-generated decoder. */ 2003878cc677SRichard Henderson #include "decode-insns.c.inc" 2004878cc677SRichard Henderson 2005878cc677SRichard Henderson #define TRANS(NAME, AVAIL, FUNC, ...) \ 2006878cc677SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_##NAME *a) \ 2007878cc677SRichard Henderson { return avail_##AVAIL(dc) && FUNC(dc, __VA_ARGS__); } 2008878cc677SRichard Henderson 2009878cc677SRichard Henderson #define avail_ALL(C) true 2010878cc677SRichard Henderson #ifdef TARGET_SPARC64 2011878cc677SRichard Henderson # define avail_32(C) false 2012af25071cSRichard Henderson # define avail_ASR17(C) false 2013d0a11d25SRichard Henderson # define avail_CASA(C) true 2014c2636853SRichard Henderson # define avail_DIV(C) true 2015b5372650SRichard Henderson # define avail_MUL(C) true 20160faef01bSRichard Henderson # define avail_POWERDOWN(C) false 2017878cc677SRichard Henderson # define avail_64(C) true 20185d617bfbSRichard Henderson # define avail_GL(C) ((C)->def->features & CPU_FEATURE_GL) 2019af25071cSRichard Henderson # define avail_HYPV(C) ((C)->def->features & CPU_FEATURE_HYPV) 2020b88ce6f2SRichard Henderson # define avail_VIS1(C) ((C)->def->features & CPU_FEATURE_VIS1) 2021b88ce6f2SRichard Henderson # define avail_VIS2(C) ((C)->def->features & CPU_FEATURE_VIS2) 2022878cc677SRichard Henderson #else 2023878cc677SRichard Henderson # define avail_32(C) true 2024af25071cSRichard Henderson # define avail_ASR17(C) ((C)->def->features & CPU_FEATURE_ASR17) 2025d0a11d25SRichard Henderson # define avail_CASA(C) ((C)->def->features & CPU_FEATURE_CASA) 2026c2636853SRichard Henderson # define avail_DIV(C) ((C)->def->features & CPU_FEATURE_DIV) 2027b5372650SRichard Henderson # define avail_MUL(C) ((C)->def->features & CPU_FEATURE_MUL) 20280faef01bSRichard Henderson # define avail_POWERDOWN(C) ((C)->def->features & CPU_FEATURE_POWERDOWN) 2029878cc677SRichard Henderson # define avail_64(C) false 20305d617bfbSRichard Henderson # define avail_GL(C) false 2031af25071cSRichard Henderson # define avail_HYPV(C) false 2032b88ce6f2SRichard Henderson # define avail_VIS1(C) false 2033b88ce6f2SRichard Henderson # define avail_VIS2(C) false 2034878cc677SRichard Henderson #endif 2035878cc677SRichard Henderson 2036878cc677SRichard Henderson /* Default case for non jump instructions. */ 2037878cc677SRichard Henderson static bool advance_pc(DisasContext *dc) 2038878cc677SRichard Henderson { 20394a8d145dSRichard Henderson TCGLabel *l1; 20404a8d145dSRichard Henderson 204189527e3aSRichard Henderson finishing_insn(dc); 204289527e3aSRichard Henderson 2043878cc677SRichard Henderson if (dc->npc & 3) { 2044878cc677SRichard Henderson switch (dc->npc) { 2045878cc677SRichard Henderson case DYNAMIC_PC: 2046878cc677SRichard Henderson case DYNAMIC_PC_LOOKUP: 2047878cc677SRichard Henderson dc->pc = dc->npc; 2048444d8b30SRichard Henderson tcg_gen_mov_tl(cpu_pc, cpu_npc); 2049444d8b30SRichard Henderson tcg_gen_addi_tl(cpu_npc, cpu_npc, 4); 2050878cc677SRichard Henderson break; 20514a8d145dSRichard Henderson 2052878cc677SRichard Henderson case JUMP_PC: 2053878cc677SRichard Henderson /* we can do a static jump */ 20544a8d145dSRichard Henderson l1 = gen_new_label(); 2055533f042fSRichard Henderson tcg_gen_brcondi_tl(dc->jump.cond, dc->jump.c1, dc->jump.c2, l1); 20564a8d145dSRichard Henderson 20574a8d145dSRichard Henderson /* jump not taken */ 20584a8d145dSRichard Henderson gen_goto_tb(dc, 1, dc->jump_pc[1], dc->jump_pc[1] + 4); 20594a8d145dSRichard Henderson 20604a8d145dSRichard Henderson /* jump taken */ 20614a8d145dSRichard Henderson gen_set_label(l1); 20624a8d145dSRichard Henderson gen_goto_tb(dc, 0, dc->jump_pc[0], dc->jump_pc[0] + 4); 20634a8d145dSRichard Henderson 2064878cc677SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 2065878cc677SRichard Henderson break; 20664a8d145dSRichard Henderson 2067878cc677SRichard Henderson default: 2068878cc677SRichard Henderson g_assert_not_reached(); 2069878cc677SRichard Henderson } 2070878cc677SRichard Henderson } else { 2071878cc677SRichard Henderson dc->pc = dc->npc; 2072878cc677SRichard Henderson dc->npc = dc->npc + 4; 2073878cc677SRichard Henderson } 2074878cc677SRichard Henderson return true; 2075878cc677SRichard Henderson } 2076878cc677SRichard Henderson 20776d2a0768SRichard Henderson /* 20786d2a0768SRichard Henderson * Major opcodes 00 and 01 -- branches, call, and sethi 20796d2a0768SRichard Henderson */ 20806d2a0768SRichard Henderson 20819d4e2bc7SRichard Henderson static bool advance_jump_cond(DisasContext *dc, DisasCompare *cmp, 20823951b7a8SRichard Henderson bool annul, int disp) 2083276567aaSRichard Henderson { 20843951b7a8SRichard Henderson target_ulong dest = address_mask_i(dc, dc->pc + disp * 4); 2085c76c8045SRichard Henderson target_ulong npc; 2086c76c8045SRichard Henderson 208789527e3aSRichard Henderson finishing_insn(dc); 208889527e3aSRichard Henderson 20892d9bb237SRichard Henderson if (cmp->cond == TCG_COND_ALWAYS) { 20902d9bb237SRichard Henderson if (annul) { 20912d9bb237SRichard Henderson dc->pc = dest; 20922d9bb237SRichard Henderson dc->npc = dest + 4; 20932d9bb237SRichard Henderson } else { 20942d9bb237SRichard Henderson gen_mov_pc_npc(dc); 20952d9bb237SRichard Henderson dc->npc = dest; 20962d9bb237SRichard Henderson } 20972d9bb237SRichard Henderson return true; 20982d9bb237SRichard Henderson } 20992d9bb237SRichard Henderson 21002d9bb237SRichard Henderson if (cmp->cond == TCG_COND_NEVER) { 21012d9bb237SRichard Henderson npc = dc->npc; 21022d9bb237SRichard Henderson if (npc & 3) { 21032d9bb237SRichard Henderson gen_mov_pc_npc(dc); 21042d9bb237SRichard Henderson if (annul) { 21052d9bb237SRichard Henderson tcg_gen_addi_tl(cpu_pc, cpu_pc, 4); 21062d9bb237SRichard Henderson } 21072d9bb237SRichard Henderson tcg_gen_addi_tl(cpu_npc, cpu_pc, 4); 21082d9bb237SRichard Henderson } else { 21092d9bb237SRichard Henderson dc->pc = npc + (annul ? 4 : 0); 21102d9bb237SRichard Henderson dc->npc = dc->pc + 4; 21112d9bb237SRichard Henderson } 21122d9bb237SRichard Henderson return true; 21132d9bb237SRichard Henderson } 21142d9bb237SRichard Henderson 2115c76c8045SRichard Henderson flush_cond(dc); 2116c76c8045SRichard Henderson npc = dc->npc; 21176b3e4cc6SRichard Henderson 2118276567aaSRichard Henderson if (annul) { 21196b3e4cc6SRichard Henderson TCGLabel *l1 = gen_new_label(); 21206b3e4cc6SRichard Henderson 2121c8507ebfSRichard Henderson tcg_gen_brcondi_tl(tcg_invert_cond(cmp->cond), cmp->c1, cmp->c2, l1); 21226b3e4cc6SRichard Henderson gen_goto_tb(dc, 0, npc, dest); 21236b3e4cc6SRichard Henderson gen_set_label(l1); 21246b3e4cc6SRichard Henderson gen_goto_tb(dc, 1, npc + 4, npc + 8); 21256b3e4cc6SRichard Henderson 21266b3e4cc6SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 2127276567aaSRichard Henderson } else { 21286b3e4cc6SRichard Henderson if (npc & 3) { 21296b3e4cc6SRichard Henderson switch (npc) { 21306b3e4cc6SRichard Henderson case DYNAMIC_PC: 21316b3e4cc6SRichard Henderson case DYNAMIC_PC_LOOKUP: 21326b3e4cc6SRichard Henderson tcg_gen_mov_tl(cpu_pc, cpu_npc); 21336b3e4cc6SRichard Henderson tcg_gen_addi_tl(cpu_npc, cpu_npc, 4); 21349d4e2bc7SRichard Henderson tcg_gen_movcond_tl(cmp->cond, cpu_npc, 2135c8507ebfSRichard Henderson cmp->c1, tcg_constant_tl(cmp->c2), 21366b3e4cc6SRichard Henderson tcg_constant_tl(dest), cpu_npc); 21376b3e4cc6SRichard Henderson dc->pc = npc; 21386b3e4cc6SRichard Henderson break; 21396b3e4cc6SRichard Henderson default: 21406b3e4cc6SRichard Henderson g_assert_not_reached(); 21416b3e4cc6SRichard Henderson } 21426b3e4cc6SRichard Henderson } else { 21436b3e4cc6SRichard Henderson dc->pc = npc; 2144533f042fSRichard Henderson dc->npc = JUMP_PC; 2145533f042fSRichard Henderson dc->jump = *cmp; 21466b3e4cc6SRichard Henderson dc->jump_pc[0] = dest; 21476b3e4cc6SRichard Henderson dc->jump_pc[1] = npc + 4; 2148dd7dbfccSRichard Henderson 2149dd7dbfccSRichard Henderson /* The condition for cpu_cond is always NE -- normalize. */ 2150dd7dbfccSRichard Henderson if (cmp->cond == TCG_COND_NE) { 2151c8507ebfSRichard Henderson tcg_gen_xori_tl(cpu_cond, cmp->c1, cmp->c2); 21529d4e2bc7SRichard Henderson } else { 2153c8507ebfSRichard Henderson tcg_gen_setcondi_tl(cmp->cond, cpu_cond, cmp->c1, cmp->c2); 21549d4e2bc7SRichard Henderson } 215589527e3aSRichard Henderson dc->cpu_cond_live = true; 21566b3e4cc6SRichard Henderson } 2157276567aaSRichard Henderson } 2158276567aaSRichard Henderson return true; 2159276567aaSRichard Henderson } 2160276567aaSRichard Henderson 2161af25071cSRichard Henderson static bool raise_priv(DisasContext *dc) 2162af25071cSRichard Henderson { 2163af25071cSRichard Henderson gen_exception(dc, TT_PRIV_INSN); 2164af25071cSRichard Henderson return true; 2165af25071cSRichard Henderson } 2166af25071cSRichard Henderson 216706c060d9SRichard Henderson static bool raise_unimpfpop(DisasContext *dc) 216806c060d9SRichard Henderson { 216906c060d9SRichard Henderson gen_op_fpexception_im(dc, FSR_FTT_UNIMPFPOP); 217006c060d9SRichard Henderson return true; 217106c060d9SRichard Henderson } 217206c060d9SRichard Henderson 217306c060d9SRichard Henderson static bool gen_trap_float128(DisasContext *dc) 217406c060d9SRichard Henderson { 217506c060d9SRichard Henderson if (dc->def->features & CPU_FEATURE_FLOAT128) { 217606c060d9SRichard Henderson return false; 217706c060d9SRichard Henderson } 217806c060d9SRichard Henderson return raise_unimpfpop(dc); 217906c060d9SRichard Henderson } 218006c060d9SRichard Henderson 2181276567aaSRichard Henderson static bool do_bpcc(DisasContext *dc, arg_bcc *a) 2182276567aaSRichard Henderson { 21831ea9c62aSRichard Henderson DisasCompare cmp; 2184276567aaSRichard Henderson 21851ea9c62aSRichard Henderson gen_compare(&cmp, a->cc, a->cond, dc); 21863951b7a8SRichard Henderson return advance_jump_cond(dc, &cmp, a->a, a->i); 2187276567aaSRichard Henderson } 2188276567aaSRichard Henderson 2189276567aaSRichard Henderson TRANS(Bicc, ALL, do_bpcc, a) 2190276567aaSRichard Henderson TRANS(BPcc, 64, do_bpcc, a) 2191276567aaSRichard Henderson 219245196ea4SRichard Henderson static bool do_fbpfcc(DisasContext *dc, arg_bcc *a) 219345196ea4SRichard Henderson { 2194d5471936SRichard Henderson DisasCompare cmp; 219545196ea4SRichard Henderson 219645196ea4SRichard Henderson if (gen_trap_ifnofpu(dc)) { 219745196ea4SRichard Henderson return true; 219845196ea4SRichard Henderson } 2199d5471936SRichard Henderson gen_fcompare(&cmp, a->cc, a->cond); 22003951b7a8SRichard Henderson return advance_jump_cond(dc, &cmp, a->a, a->i); 220145196ea4SRichard Henderson } 220245196ea4SRichard Henderson 220345196ea4SRichard Henderson TRANS(FBPfcc, 64, do_fbpfcc, a) 220445196ea4SRichard Henderson TRANS(FBfcc, ALL, do_fbpfcc, a) 220545196ea4SRichard Henderson 2206ab9ffe98SRichard Henderson static bool trans_BPr(DisasContext *dc, arg_BPr *a) 2207ab9ffe98SRichard Henderson { 2208ab9ffe98SRichard Henderson DisasCompare cmp; 2209ab9ffe98SRichard Henderson 2210ab9ffe98SRichard Henderson if (!avail_64(dc)) { 2211ab9ffe98SRichard Henderson return false; 2212ab9ffe98SRichard Henderson } 22132c4f56c9SRichard Henderson if (!gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1))) { 2214ab9ffe98SRichard Henderson return false; 2215ab9ffe98SRichard Henderson } 22163951b7a8SRichard Henderson return advance_jump_cond(dc, &cmp, a->a, a->i); 2217ab9ffe98SRichard Henderson } 2218ab9ffe98SRichard Henderson 221923ada1b1SRichard Henderson static bool trans_CALL(DisasContext *dc, arg_CALL *a) 222023ada1b1SRichard Henderson { 222123ada1b1SRichard Henderson target_long target = address_mask_i(dc, dc->pc + a->i * 4); 222223ada1b1SRichard Henderson 222323ada1b1SRichard Henderson gen_store_gpr(dc, 15, tcg_constant_tl(dc->pc)); 222423ada1b1SRichard Henderson gen_mov_pc_npc(dc); 222523ada1b1SRichard Henderson dc->npc = target; 222623ada1b1SRichard Henderson return true; 222723ada1b1SRichard Henderson } 222823ada1b1SRichard Henderson 222945196ea4SRichard Henderson static bool trans_NCP(DisasContext *dc, arg_NCP *a) 223045196ea4SRichard Henderson { 223145196ea4SRichard Henderson /* 223245196ea4SRichard Henderson * For sparc32, always generate the no-coprocessor exception. 223345196ea4SRichard Henderson * For sparc64, always generate illegal instruction. 223445196ea4SRichard Henderson */ 223545196ea4SRichard Henderson #ifdef TARGET_SPARC64 223645196ea4SRichard Henderson return false; 223745196ea4SRichard Henderson #else 223845196ea4SRichard Henderson gen_exception(dc, TT_NCP_INSN); 223945196ea4SRichard Henderson return true; 224045196ea4SRichard Henderson #endif 224145196ea4SRichard Henderson } 224245196ea4SRichard Henderson 22436d2a0768SRichard Henderson static bool trans_SETHI(DisasContext *dc, arg_SETHI *a) 22446d2a0768SRichard Henderson { 22456d2a0768SRichard Henderson /* Special-case %g0 because that's the canonical nop. */ 22466d2a0768SRichard Henderson if (a->rd) { 22476d2a0768SRichard Henderson gen_store_gpr(dc, a->rd, tcg_constant_tl((uint32_t)a->i << 10)); 22486d2a0768SRichard Henderson } 22496d2a0768SRichard Henderson return advance_pc(dc); 22506d2a0768SRichard Henderson } 22516d2a0768SRichard Henderson 22520faef01bSRichard Henderson /* 22530faef01bSRichard Henderson * Major Opcode 10 -- integer, floating-point, vis, and system insns. 22540faef01bSRichard Henderson */ 22550faef01bSRichard Henderson 225630376636SRichard Henderson static bool do_tcc(DisasContext *dc, int cond, int cc, 225730376636SRichard Henderson int rs1, bool imm, int rs2_or_imm) 225830376636SRichard Henderson { 225930376636SRichard Henderson int mask = ((dc->def->features & CPU_FEATURE_HYPV) && supervisor(dc) 226030376636SRichard Henderson ? UA2005_HTRAP_MASK : V8_TRAP_MASK); 226130376636SRichard Henderson DisasCompare cmp; 226230376636SRichard Henderson TCGLabel *lab; 226330376636SRichard Henderson TCGv_i32 trap; 226430376636SRichard Henderson 226530376636SRichard Henderson /* Trap never. */ 226630376636SRichard Henderson if (cond == 0) { 226730376636SRichard Henderson return advance_pc(dc); 226830376636SRichard Henderson } 226930376636SRichard Henderson 227030376636SRichard Henderson /* 227130376636SRichard Henderson * Immediate traps are the most common case. Since this value is 227230376636SRichard Henderson * live across the branch, it really pays to evaluate the constant. 227330376636SRichard Henderson */ 227430376636SRichard Henderson if (rs1 == 0 && (imm || rs2_or_imm == 0)) { 227530376636SRichard Henderson trap = tcg_constant_i32((rs2_or_imm & mask) + TT_TRAP); 227630376636SRichard Henderson } else { 227730376636SRichard Henderson trap = tcg_temp_new_i32(); 227830376636SRichard Henderson tcg_gen_trunc_tl_i32(trap, gen_load_gpr(dc, rs1)); 227930376636SRichard Henderson if (imm) { 228030376636SRichard Henderson tcg_gen_addi_i32(trap, trap, rs2_or_imm); 228130376636SRichard Henderson } else { 228230376636SRichard Henderson TCGv_i32 t2 = tcg_temp_new_i32(); 228330376636SRichard Henderson tcg_gen_trunc_tl_i32(t2, gen_load_gpr(dc, rs2_or_imm)); 228430376636SRichard Henderson tcg_gen_add_i32(trap, trap, t2); 228530376636SRichard Henderson } 228630376636SRichard Henderson tcg_gen_andi_i32(trap, trap, mask); 228730376636SRichard Henderson tcg_gen_addi_i32(trap, trap, TT_TRAP); 228830376636SRichard Henderson } 228930376636SRichard Henderson 229089527e3aSRichard Henderson finishing_insn(dc); 229189527e3aSRichard Henderson 229230376636SRichard Henderson /* Trap always. */ 229330376636SRichard Henderson if (cond == 8) { 229430376636SRichard Henderson save_state(dc); 229530376636SRichard Henderson gen_helper_raise_exception(tcg_env, trap); 229630376636SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 229730376636SRichard Henderson return true; 229830376636SRichard Henderson } 229930376636SRichard Henderson 230030376636SRichard Henderson /* Conditional trap. */ 230130376636SRichard Henderson flush_cond(dc); 230230376636SRichard Henderson lab = delay_exceptionv(dc, trap); 230330376636SRichard Henderson gen_compare(&cmp, cc, cond, dc); 2304c8507ebfSRichard Henderson tcg_gen_brcondi_tl(cmp.cond, cmp.c1, cmp.c2, lab); 230530376636SRichard Henderson 230630376636SRichard Henderson return advance_pc(dc); 230730376636SRichard Henderson } 230830376636SRichard Henderson 230930376636SRichard Henderson static bool trans_Tcc_r(DisasContext *dc, arg_Tcc_r *a) 231030376636SRichard Henderson { 231130376636SRichard Henderson if (avail_32(dc) && a->cc) { 231230376636SRichard Henderson return false; 231330376636SRichard Henderson } 231430376636SRichard Henderson return do_tcc(dc, a->cond, a->cc, a->rs1, false, a->rs2); 231530376636SRichard Henderson } 231630376636SRichard Henderson 231730376636SRichard Henderson static bool trans_Tcc_i_v7(DisasContext *dc, arg_Tcc_i_v7 *a) 231830376636SRichard Henderson { 231930376636SRichard Henderson if (avail_64(dc)) { 232030376636SRichard Henderson return false; 232130376636SRichard Henderson } 232230376636SRichard Henderson return do_tcc(dc, a->cond, 0, a->rs1, true, a->i); 232330376636SRichard Henderson } 232430376636SRichard Henderson 232530376636SRichard Henderson static bool trans_Tcc_i_v9(DisasContext *dc, arg_Tcc_i_v9 *a) 232630376636SRichard Henderson { 232730376636SRichard Henderson if (avail_32(dc)) { 232830376636SRichard Henderson return false; 232930376636SRichard Henderson } 233030376636SRichard Henderson return do_tcc(dc, a->cond, a->cc, a->rs1, true, a->i); 233130376636SRichard Henderson } 233230376636SRichard Henderson 2333af25071cSRichard Henderson static bool trans_STBAR(DisasContext *dc, arg_STBAR *a) 2334af25071cSRichard Henderson { 2335af25071cSRichard Henderson tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC); 2336af25071cSRichard Henderson return advance_pc(dc); 2337af25071cSRichard Henderson } 2338af25071cSRichard Henderson 2339af25071cSRichard Henderson static bool trans_MEMBAR(DisasContext *dc, arg_MEMBAR *a) 2340af25071cSRichard Henderson { 2341af25071cSRichard Henderson if (avail_32(dc)) { 2342af25071cSRichard Henderson return false; 2343af25071cSRichard Henderson } 2344af25071cSRichard Henderson if (a->mmask) { 2345af25071cSRichard Henderson /* Note TCG_MO_* was modeled on sparc64, so mmask matches. */ 2346af25071cSRichard Henderson tcg_gen_mb(a->mmask | TCG_BAR_SC); 2347af25071cSRichard Henderson } 2348af25071cSRichard Henderson if (a->cmask) { 2349af25071cSRichard Henderson /* For #Sync, etc, end the TB to recognize interrupts. */ 2350af25071cSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 2351af25071cSRichard Henderson } 2352af25071cSRichard Henderson return advance_pc(dc); 2353af25071cSRichard Henderson } 2354af25071cSRichard Henderson 2355af25071cSRichard Henderson static bool do_rd_special(DisasContext *dc, bool priv, int rd, 2356af25071cSRichard Henderson TCGv (*func)(DisasContext *, TCGv)) 2357af25071cSRichard Henderson { 2358af25071cSRichard Henderson if (!priv) { 2359af25071cSRichard Henderson return raise_priv(dc); 2360af25071cSRichard Henderson } 2361af25071cSRichard Henderson gen_store_gpr(dc, rd, func(dc, gen_dest_gpr(dc, rd))); 2362af25071cSRichard Henderson return advance_pc(dc); 2363af25071cSRichard Henderson } 2364af25071cSRichard Henderson 2365af25071cSRichard Henderson static TCGv do_rdy(DisasContext *dc, TCGv dst) 2366af25071cSRichard Henderson { 2367af25071cSRichard Henderson return cpu_y; 2368af25071cSRichard Henderson } 2369af25071cSRichard Henderson 2370af25071cSRichard Henderson static bool trans_RDY(DisasContext *dc, arg_RDY *a) 2371af25071cSRichard Henderson { 2372af25071cSRichard Henderson /* 2373af25071cSRichard Henderson * TODO: Need a feature bit for sparcv8. In the meantime, treat all 2374af25071cSRichard Henderson * 32-bit cpus like sparcv7, which ignores the rs1 field. 2375af25071cSRichard Henderson * This matches after all other ASR, so Leon3 Asr17 is handled first. 2376af25071cSRichard Henderson */ 2377af25071cSRichard Henderson if (avail_64(dc) && a->rs1 != 0) { 2378af25071cSRichard Henderson return false; 2379af25071cSRichard Henderson } 2380af25071cSRichard Henderson return do_rd_special(dc, true, a->rd, do_rdy); 2381af25071cSRichard Henderson } 2382af25071cSRichard Henderson 2383af25071cSRichard Henderson static TCGv do_rd_leon3_config(DisasContext *dc, TCGv dst) 2384af25071cSRichard Henderson { 2385af25071cSRichard Henderson uint32_t val; 2386af25071cSRichard Henderson 2387af25071cSRichard Henderson /* 2388af25071cSRichard Henderson * TODO: There are many more fields to be filled, 2389af25071cSRichard Henderson * some of which are writable. 2390af25071cSRichard Henderson */ 2391af25071cSRichard Henderson val = dc->def->nwindows - 1; /* [4:0] NWIN */ 2392af25071cSRichard Henderson val |= 1 << 8; /* [8] V8 */ 2393af25071cSRichard Henderson 2394af25071cSRichard Henderson return tcg_constant_tl(val); 2395af25071cSRichard Henderson } 2396af25071cSRichard Henderson 2397af25071cSRichard Henderson TRANS(RDASR17, ASR17, do_rd_special, true, a->rd, do_rd_leon3_config) 2398af25071cSRichard Henderson 2399af25071cSRichard Henderson static TCGv do_rdccr(DisasContext *dc, TCGv dst) 2400af25071cSRichard Henderson { 2401af25071cSRichard Henderson gen_helper_rdccr(dst, tcg_env); 2402af25071cSRichard Henderson return dst; 2403af25071cSRichard Henderson } 2404af25071cSRichard Henderson 2405af25071cSRichard Henderson TRANS(RDCCR, 64, do_rd_special, true, a->rd, do_rdccr) 2406af25071cSRichard Henderson 2407af25071cSRichard Henderson static TCGv do_rdasi(DisasContext *dc, TCGv dst) 2408af25071cSRichard Henderson { 2409af25071cSRichard Henderson #ifdef TARGET_SPARC64 2410af25071cSRichard Henderson return tcg_constant_tl(dc->asi); 2411af25071cSRichard Henderson #else 2412af25071cSRichard Henderson qemu_build_not_reached(); 2413af25071cSRichard Henderson #endif 2414af25071cSRichard Henderson } 2415af25071cSRichard Henderson 2416af25071cSRichard Henderson TRANS(RDASI, 64, do_rd_special, true, a->rd, do_rdasi) 2417af25071cSRichard Henderson 2418af25071cSRichard Henderson static TCGv do_rdtick(DisasContext *dc, TCGv dst) 2419af25071cSRichard Henderson { 2420af25071cSRichard Henderson TCGv_ptr r_tickptr = tcg_temp_new_ptr(); 2421af25071cSRichard Henderson 2422af25071cSRichard Henderson tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick)); 2423af25071cSRichard Henderson if (translator_io_start(&dc->base)) { 2424af25071cSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 2425af25071cSRichard Henderson } 2426af25071cSRichard Henderson gen_helper_tick_get_count(dst, tcg_env, r_tickptr, 2427af25071cSRichard Henderson tcg_constant_i32(dc->mem_idx)); 2428af25071cSRichard Henderson return dst; 2429af25071cSRichard Henderson } 2430af25071cSRichard Henderson 2431af25071cSRichard Henderson /* TODO: non-priv access only allowed when enabled. */ 2432af25071cSRichard Henderson TRANS(RDTICK, 64, do_rd_special, true, a->rd, do_rdtick) 2433af25071cSRichard Henderson 2434af25071cSRichard Henderson static TCGv do_rdpc(DisasContext *dc, TCGv dst) 2435af25071cSRichard Henderson { 2436af25071cSRichard Henderson return tcg_constant_tl(address_mask_i(dc, dc->pc)); 2437af25071cSRichard Henderson } 2438af25071cSRichard Henderson 2439af25071cSRichard Henderson TRANS(RDPC, 64, do_rd_special, true, a->rd, do_rdpc) 2440af25071cSRichard Henderson 2441af25071cSRichard Henderson static TCGv do_rdfprs(DisasContext *dc, TCGv dst) 2442af25071cSRichard Henderson { 2443af25071cSRichard Henderson tcg_gen_ext_i32_tl(dst, cpu_fprs); 2444af25071cSRichard Henderson return dst; 2445af25071cSRichard Henderson } 2446af25071cSRichard Henderson 2447af25071cSRichard Henderson TRANS(RDFPRS, 64, do_rd_special, true, a->rd, do_rdfprs) 2448af25071cSRichard Henderson 2449af25071cSRichard Henderson static TCGv do_rdgsr(DisasContext *dc, TCGv dst) 2450af25071cSRichard Henderson { 2451af25071cSRichard Henderson gen_trap_ifnofpu(dc); 2452af25071cSRichard Henderson return cpu_gsr; 2453af25071cSRichard Henderson } 2454af25071cSRichard Henderson 2455af25071cSRichard Henderson TRANS(RDGSR, 64, do_rd_special, true, a->rd, do_rdgsr) 2456af25071cSRichard Henderson 2457af25071cSRichard Henderson static TCGv do_rdsoftint(DisasContext *dc, TCGv dst) 2458af25071cSRichard Henderson { 2459af25071cSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(softint)); 2460af25071cSRichard Henderson return dst; 2461af25071cSRichard Henderson } 2462af25071cSRichard Henderson 2463af25071cSRichard Henderson TRANS(RDSOFTINT, 64, do_rd_special, supervisor(dc), a->rd, do_rdsoftint) 2464af25071cSRichard Henderson 2465af25071cSRichard Henderson static TCGv do_rdtick_cmpr(DisasContext *dc, TCGv dst) 2466af25071cSRichard Henderson { 2467577efa45SRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(tick_cmpr)); 2468577efa45SRichard Henderson return dst; 2469af25071cSRichard Henderson } 2470af25071cSRichard Henderson 2471af25071cSRichard Henderson /* TODO: non-priv access only allowed when enabled. */ 2472af25071cSRichard Henderson TRANS(RDTICK_CMPR, 64, do_rd_special, true, a->rd, do_rdtick_cmpr) 2473af25071cSRichard Henderson 2474af25071cSRichard Henderson static TCGv do_rdstick(DisasContext *dc, TCGv dst) 2475af25071cSRichard Henderson { 2476af25071cSRichard Henderson TCGv_ptr r_tickptr = tcg_temp_new_ptr(); 2477af25071cSRichard Henderson 2478af25071cSRichard Henderson tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(stick)); 2479af25071cSRichard Henderson if (translator_io_start(&dc->base)) { 2480af25071cSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 2481af25071cSRichard Henderson } 2482af25071cSRichard Henderson gen_helper_tick_get_count(dst, tcg_env, r_tickptr, 2483af25071cSRichard Henderson tcg_constant_i32(dc->mem_idx)); 2484af25071cSRichard Henderson return dst; 2485af25071cSRichard Henderson } 2486af25071cSRichard Henderson 2487af25071cSRichard Henderson /* TODO: non-priv access only allowed when enabled. */ 2488af25071cSRichard Henderson TRANS(RDSTICK, 64, do_rd_special, true, a->rd, do_rdstick) 2489af25071cSRichard Henderson 2490af25071cSRichard Henderson static TCGv do_rdstick_cmpr(DisasContext *dc, TCGv dst) 2491af25071cSRichard Henderson { 2492577efa45SRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(stick_cmpr)); 2493577efa45SRichard Henderson return dst; 2494af25071cSRichard Henderson } 2495af25071cSRichard Henderson 2496af25071cSRichard Henderson /* TODO: supervisor access only allowed when enabled by hypervisor. */ 2497af25071cSRichard Henderson TRANS(RDSTICK_CMPR, 64, do_rd_special, supervisor(dc), a->rd, do_rdstick_cmpr) 2498af25071cSRichard Henderson 2499af25071cSRichard Henderson /* 2500af25071cSRichard Henderson * UltraSPARC-T1 Strand status. 2501af25071cSRichard Henderson * HYPV check maybe not enough, UA2005 & UA2007 describe 2502af25071cSRichard Henderson * this ASR as impl. dep 2503af25071cSRichard Henderson */ 2504af25071cSRichard Henderson static TCGv do_rdstrand_status(DisasContext *dc, TCGv dst) 2505af25071cSRichard Henderson { 2506af25071cSRichard Henderson return tcg_constant_tl(1); 2507af25071cSRichard Henderson } 2508af25071cSRichard Henderson 2509af25071cSRichard Henderson TRANS(RDSTRAND_STATUS, HYPV, do_rd_special, true, a->rd, do_rdstrand_status) 2510af25071cSRichard Henderson 2511668bb9b7SRichard Henderson static TCGv do_rdpsr(DisasContext *dc, TCGv dst) 2512668bb9b7SRichard Henderson { 2513668bb9b7SRichard Henderson gen_helper_rdpsr(dst, tcg_env); 2514668bb9b7SRichard Henderson return dst; 2515668bb9b7SRichard Henderson } 2516668bb9b7SRichard Henderson 2517668bb9b7SRichard Henderson TRANS(RDPSR, 32, do_rd_special, supervisor(dc), a->rd, do_rdpsr) 2518668bb9b7SRichard Henderson 2519668bb9b7SRichard Henderson static TCGv do_rdhpstate(DisasContext *dc, TCGv dst) 2520668bb9b7SRichard Henderson { 2521668bb9b7SRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hpstate)); 2522668bb9b7SRichard Henderson return dst; 2523668bb9b7SRichard Henderson } 2524668bb9b7SRichard Henderson 2525668bb9b7SRichard Henderson TRANS(RDHPR_hpstate, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhpstate) 2526668bb9b7SRichard Henderson 2527668bb9b7SRichard Henderson static TCGv do_rdhtstate(DisasContext *dc, TCGv dst) 2528668bb9b7SRichard Henderson { 2529668bb9b7SRichard Henderson TCGv_i32 tl = tcg_temp_new_i32(); 2530668bb9b7SRichard Henderson TCGv_ptr tp = tcg_temp_new_ptr(); 2531668bb9b7SRichard Henderson 2532668bb9b7SRichard Henderson tcg_gen_ld_i32(tl, tcg_env, env64_field_offsetof(tl)); 2533668bb9b7SRichard Henderson tcg_gen_andi_i32(tl, tl, MAXTL_MASK); 2534668bb9b7SRichard Henderson tcg_gen_shli_i32(tl, tl, 3); 2535668bb9b7SRichard Henderson tcg_gen_ext_i32_ptr(tp, tl); 2536668bb9b7SRichard Henderson tcg_gen_add_ptr(tp, tp, tcg_env); 2537668bb9b7SRichard Henderson 2538668bb9b7SRichard Henderson tcg_gen_ld_tl(dst, tp, env64_field_offsetof(htstate)); 2539668bb9b7SRichard Henderson return dst; 2540668bb9b7SRichard Henderson } 2541668bb9b7SRichard Henderson 2542668bb9b7SRichard Henderson TRANS(RDHPR_htstate, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhtstate) 2543668bb9b7SRichard Henderson 2544668bb9b7SRichard Henderson static TCGv do_rdhintp(DisasContext *dc, TCGv dst) 2545668bb9b7SRichard Henderson { 25462da789deSRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hintp)); 25472da789deSRichard Henderson return dst; 2548668bb9b7SRichard Henderson } 2549668bb9b7SRichard Henderson 2550668bb9b7SRichard Henderson TRANS(RDHPR_hintp, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhintp) 2551668bb9b7SRichard Henderson 2552668bb9b7SRichard Henderson static TCGv do_rdhtba(DisasContext *dc, TCGv dst) 2553668bb9b7SRichard Henderson { 25542da789deSRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(htba)); 25552da789deSRichard Henderson return dst; 2556668bb9b7SRichard Henderson } 2557668bb9b7SRichard Henderson 2558668bb9b7SRichard Henderson TRANS(RDHPR_htba, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhtba) 2559668bb9b7SRichard Henderson 2560668bb9b7SRichard Henderson static TCGv do_rdhver(DisasContext *dc, TCGv dst) 2561668bb9b7SRichard Henderson { 25622da789deSRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hver)); 25632da789deSRichard Henderson return dst; 2564668bb9b7SRichard Henderson } 2565668bb9b7SRichard Henderson 2566668bb9b7SRichard Henderson TRANS(RDHPR_hver, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdhver) 2567668bb9b7SRichard Henderson 2568668bb9b7SRichard Henderson static TCGv do_rdhstick_cmpr(DisasContext *dc, TCGv dst) 2569668bb9b7SRichard Henderson { 2570577efa45SRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(hstick_cmpr)); 2571577efa45SRichard Henderson return dst; 2572668bb9b7SRichard Henderson } 2573668bb9b7SRichard Henderson 2574668bb9b7SRichard Henderson TRANS(RDHPR_hstick_cmpr, HYPV, do_rd_special, hypervisor(dc), a->rd, 2575668bb9b7SRichard Henderson do_rdhstick_cmpr) 2576668bb9b7SRichard Henderson 25775d617bfbSRichard Henderson static TCGv do_rdwim(DisasContext *dc, TCGv dst) 25785d617bfbSRichard Henderson { 2579cd6269f7SRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env32_field_offsetof(wim)); 2580cd6269f7SRichard Henderson return dst; 25815d617bfbSRichard Henderson } 25825d617bfbSRichard Henderson 25835d617bfbSRichard Henderson TRANS(RDWIM, 32, do_rd_special, supervisor(dc), a->rd, do_rdwim) 25845d617bfbSRichard Henderson 25855d617bfbSRichard Henderson static TCGv do_rdtpc(DisasContext *dc, TCGv dst) 25865d617bfbSRichard Henderson { 25875d617bfbSRichard Henderson #ifdef TARGET_SPARC64 25885d617bfbSRichard Henderson TCGv_ptr r_tsptr = tcg_temp_new_ptr(); 25895d617bfbSRichard Henderson 25905d617bfbSRichard Henderson gen_load_trap_state_at_tl(r_tsptr); 25915d617bfbSRichard Henderson tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tpc)); 25925d617bfbSRichard Henderson return dst; 25935d617bfbSRichard Henderson #else 25945d617bfbSRichard Henderson qemu_build_not_reached(); 25955d617bfbSRichard Henderson #endif 25965d617bfbSRichard Henderson } 25975d617bfbSRichard Henderson 25985d617bfbSRichard Henderson TRANS(RDPR_tpc, 64, do_rd_special, supervisor(dc), a->rd, do_rdtpc) 25995d617bfbSRichard Henderson 26005d617bfbSRichard Henderson static TCGv do_rdtnpc(DisasContext *dc, TCGv dst) 26015d617bfbSRichard Henderson { 26025d617bfbSRichard Henderson #ifdef TARGET_SPARC64 26035d617bfbSRichard Henderson TCGv_ptr r_tsptr = tcg_temp_new_ptr(); 26045d617bfbSRichard Henderson 26055d617bfbSRichard Henderson gen_load_trap_state_at_tl(r_tsptr); 26065d617bfbSRichard Henderson tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tnpc)); 26075d617bfbSRichard Henderson return dst; 26085d617bfbSRichard Henderson #else 26095d617bfbSRichard Henderson qemu_build_not_reached(); 26105d617bfbSRichard Henderson #endif 26115d617bfbSRichard Henderson } 26125d617bfbSRichard Henderson 26135d617bfbSRichard Henderson TRANS(RDPR_tnpc, 64, do_rd_special, supervisor(dc), a->rd, do_rdtnpc) 26145d617bfbSRichard Henderson 26155d617bfbSRichard Henderson static TCGv do_rdtstate(DisasContext *dc, TCGv dst) 26165d617bfbSRichard Henderson { 26175d617bfbSRichard Henderson #ifdef TARGET_SPARC64 26185d617bfbSRichard Henderson TCGv_ptr r_tsptr = tcg_temp_new_ptr(); 26195d617bfbSRichard Henderson 26205d617bfbSRichard Henderson gen_load_trap_state_at_tl(r_tsptr); 26215d617bfbSRichard Henderson tcg_gen_ld_tl(dst, r_tsptr, offsetof(trap_state, tstate)); 26225d617bfbSRichard Henderson return dst; 26235d617bfbSRichard Henderson #else 26245d617bfbSRichard Henderson qemu_build_not_reached(); 26255d617bfbSRichard Henderson #endif 26265d617bfbSRichard Henderson } 26275d617bfbSRichard Henderson 26285d617bfbSRichard Henderson TRANS(RDPR_tstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdtstate) 26295d617bfbSRichard Henderson 26305d617bfbSRichard Henderson static TCGv do_rdtt(DisasContext *dc, TCGv dst) 26315d617bfbSRichard Henderson { 26325d617bfbSRichard Henderson #ifdef TARGET_SPARC64 26335d617bfbSRichard Henderson TCGv_ptr r_tsptr = tcg_temp_new_ptr(); 26345d617bfbSRichard Henderson 26355d617bfbSRichard Henderson gen_load_trap_state_at_tl(r_tsptr); 26365d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, r_tsptr, offsetof(trap_state, tt)); 26375d617bfbSRichard Henderson return dst; 26385d617bfbSRichard Henderson #else 26395d617bfbSRichard Henderson qemu_build_not_reached(); 26405d617bfbSRichard Henderson #endif 26415d617bfbSRichard Henderson } 26425d617bfbSRichard Henderson 26435d617bfbSRichard Henderson TRANS(RDPR_tt, 64, do_rd_special, supervisor(dc), a->rd, do_rdtt) 26445d617bfbSRichard Henderson TRANS(RDPR_tick, 64, do_rd_special, supervisor(dc), a->rd, do_rdtick) 26455d617bfbSRichard Henderson 26465d617bfbSRichard Henderson static TCGv do_rdtba(DisasContext *dc, TCGv dst) 26475d617bfbSRichard Henderson { 26485d617bfbSRichard Henderson return cpu_tbr; 26495d617bfbSRichard Henderson } 26505d617bfbSRichard Henderson 2651e8325dc0SRichard Henderson TRANS(RDTBR, 32, do_rd_special, supervisor(dc), a->rd, do_rdtba) 26525d617bfbSRichard Henderson TRANS(RDPR_tba, 64, do_rd_special, supervisor(dc), a->rd, do_rdtba) 26535d617bfbSRichard Henderson 26545d617bfbSRichard Henderson static TCGv do_rdpstate(DisasContext *dc, TCGv dst) 26555d617bfbSRichard Henderson { 26565d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(pstate)); 26575d617bfbSRichard Henderson return dst; 26585d617bfbSRichard Henderson } 26595d617bfbSRichard Henderson 26605d617bfbSRichard Henderson TRANS(RDPR_pstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdpstate) 26615d617bfbSRichard Henderson 26625d617bfbSRichard Henderson static TCGv do_rdtl(DisasContext *dc, TCGv dst) 26635d617bfbSRichard Henderson { 26645d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(tl)); 26655d617bfbSRichard Henderson return dst; 26665d617bfbSRichard Henderson } 26675d617bfbSRichard Henderson 26685d617bfbSRichard Henderson TRANS(RDPR_tl, 64, do_rd_special, supervisor(dc), a->rd, do_rdtl) 26695d617bfbSRichard Henderson 26705d617bfbSRichard Henderson static TCGv do_rdpil(DisasContext *dc, TCGv dst) 26715d617bfbSRichard Henderson { 26725d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env_field_offsetof(psrpil)); 26735d617bfbSRichard Henderson return dst; 26745d617bfbSRichard Henderson } 26755d617bfbSRichard Henderson 26765d617bfbSRichard Henderson TRANS(RDPR_pil, 64, do_rd_special, supervisor(dc), a->rd, do_rdpil) 26775d617bfbSRichard Henderson 26785d617bfbSRichard Henderson static TCGv do_rdcwp(DisasContext *dc, TCGv dst) 26795d617bfbSRichard Henderson { 26805d617bfbSRichard Henderson gen_helper_rdcwp(dst, tcg_env); 26815d617bfbSRichard Henderson return dst; 26825d617bfbSRichard Henderson } 26835d617bfbSRichard Henderson 26845d617bfbSRichard Henderson TRANS(RDPR_cwp, 64, do_rd_special, supervisor(dc), a->rd, do_rdcwp) 26855d617bfbSRichard Henderson 26865d617bfbSRichard Henderson static TCGv do_rdcansave(DisasContext *dc, TCGv dst) 26875d617bfbSRichard Henderson { 26885d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(cansave)); 26895d617bfbSRichard Henderson return dst; 26905d617bfbSRichard Henderson } 26915d617bfbSRichard Henderson 26925d617bfbSRichard Henderson TRANS(RDPR_cansave, 64, do_rd_special, supervisor(dc), a->rd, do_rdcansave) 26935d617bfbSRichard Henderson 26945d617bfbSRichard Henderson static TCGv do_rdcanrestore(DisasContext *dc, TCGv dst) 26955d617bfbSRichard Henderson { 26965d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(canrestore)); 26975d617bfbSRichard Henderson return dst; 26985d617bfbSRichard Henderson } 26995d617bfbSRichard Henderson 27005d617bfbSRichard Henderson TRANS(RDPR_canrestore, 64, do_rd_special, supervisor(dc), a->rd, 27015d617bfbSRichard Henderson do_rdcanrestore) 27025d617bfbSRichard Henderson 27035d617bfbSRichard Henderson static TCGv do_rdcleanwin(DisasContext *dc, TCGv dst) 27045d617bfbSRichard Henderson { 27055d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(cleanwin)); 27065d617bfbSRichard Henderson return dst; 27075d617bfbSRichard Henderson } 27085d617bfbSRichard Henderson 27095d617bfbSRichard Henderson TRANS(RDPR_cleanwin, 64, do_rd_special, supervisor(dc), a->rd, do_rdcleanwin) 27105d617bfbSRichard Henderson 27115d617bfbSRichard Henderson static TCGv do_rdotherwin(DisasContext *dc, TCGv dst) 27125d617bfbSRichard Henderson { 27135d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(otherwin)); 27145d617bfbSRichard Henderson return dst; 27155d617bfbSRichard Henderson } 27165d617bfbSRichard Henderson 27175d617bfbSRichard Henderson TRANS(RDPR_otherwin, 64, do_rd_special, supervisor(dc), a->rd, do_rdotherwin) 27185d617bfbSRichard Henderson 27195d617bfbSRichard Henderson static TCGv do_rdwstate(DisasContext *dc, TCGv dst) 27205d617bfbSRichard Henderson { 27215d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(wstate)); 27225d617bfbSRichard Henderson return dst; 27235d617bfbSRichard Henderson } 27245d617bfbSRichard Henderson 27255d617bfbSRichard Henderson TRANS(RDPR_wstate, 64, do_rd_special, supervisor(dc), a->rd, do_rdwstate) 27265d617bfbSRichard Henderson 27275d617bfbSRichard Henderson static TCGv do_rdgl(DisasContext *dc, TCGv dst) 27285d617bfbSRichard Henderson { 27295d617bfbSRichard Henderson tcg_gen_ld32s_tl(dst, tcg_env, env64_field_offsetof(gl)); 27305d617bfbSRichard Henderson return dst; 27315d617bfbSRichard Henderson } 27325d617bfbSRichard Henderson 27335d617bfbSRichard Henderson TRANS(RDPR_gl, GL, do_rd_special, supervisor(dc), a->rd, do_rdgl) 27345d617bfbSRichard Henderson 27355d617bfbSRichard Henderson /* UA2005 strand status */ 27365d617bfbSRichard Henderson static TCGv do_rdssr(DisasContext *dc, TCGv dst) 27375d617bfbSRichard Henderson { 27382da789deSRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(ssr)); 27392da789deSRichard Henderson return dst; 27405d617bfbSRichard Henderson } 27415d617bfbSRichard Henderson 27425d617bfbSRichard Henderson TRANS(RDPR_strand_status, HYPV, do_rd_special, hypervisor(dc), a->rd, do_rdssr) 27435d617bfbSRichard Henderson 27445d617bfbSRichard Henderson static TCGv do_rdver(DisasContext *dc, TCGv dst) 27455d617bfbSRichard Henderson { 27462da789deSRichard Henderson tcg_gen_ld_tl(dst, tcg_env, env64_field_offsetof(version)); 27472da789deSRichard Henderson return dst; 27485d617bfbSRichard Henderson } 27495d617bfbSRichard Henderson 27505d617bfbSRichard Henderson TRANS(RDPR_ver, 64, do_rd_special, supervisor(dc), a->rd, do_rdver) 27515d617bfbSRichard Henderson 2752e8325dc0SRichard Henderson static bool trans_FLUSHW(DisasContext *dc, arg_FLUSHW *a) 2753e8325dc0SRichard Henderson { 2754e8325dc0SRichard Henderson if (avail_64(dc)) { 2755e8325dc0SRichard Henderson gen_helper_flushw(tcg_env); 2756e8325dc0SRichard Henderson return advance_pc(dc); 2757e8325dc0SRichard Henderson } 2758e8325dc0SRichard Henderson return false; 2759e8325dc0SRichard Henderson } 2760e8325dc0SRichard Henderson 27610faef01bSRichard Henderson static bool do_wr_special(DisasContext *dc, arg_r_r_ri *a, bool priv, 27620faef01bSRichard Henderson void (*func)(DisasContext *, TCGv)) 27630faef01bSRichard Henderson { 27640faef01bSRichard Henderson TCGv src; 27650faef01bSRichard Henderson 27660faef01bSRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 27670faef01bSRichard Henderson if (!a->imm && (a->rs2_or_imm & ~0x1f)) { 27680faef01bSRichard Henderson return false; 27690faef01bSRichard Henderson } 27700faef01bSRichard Henderson if (!priv) { 27710faef01bSRichard Henderson return raise_priv(dc); 27720faef01bSRichard Henderson } 27730faef01bSRichard Henderson 27740faef01bSRichard Henderson if (a->rs1 == 0 && (a->imm || a->rs2_or_imm == 0)) { 27750faef01bSRichard Henderson src = tcg_constant_tl(a->rs2_or_imm); 27760faef01bSRichard Henderson } else { 27770faef01bSRichard Henderson TCGv src1 = gen_load_gpr(dc, a->rs1); 27780faef01bSRichard Henderson if (a->rs2_or_imm == 0) { 27790faef01bSRichard Henderson src = src1; 27800faef01bSRichard Henderson } else { 27810faef01bSRichard Henderson src = tcg_temp_new(); 27820faef01bSRichard Henderson if (a->imm) { 27830faef01bSRichard Henderson tcg_gen_xori_tl(src, src1, a->rs2_or_imm); 27840faef01bSRichard Henderson } else { 27850faef01bSRichard Henderson tcg_gen_xor_tl(src, src1, gen_load_gpr(dc, a->rs2_or_imm)); 27860faef01bSRichard Henderson } 27870faef01bSRichard Henderson } 27880faef01bSRichard Henderson } 27890faef01bSRichard Henderson func(dc, src); 27900faef01bSRichard Henderson return advance_pc(dc); 27910faef01bSRichard Henderson } 27920faef01bSRichard Henderson 27930faef01bSRichard Henderson static void do_wry(DisasContext *dc, TCGv src) 27940faef01bSRichard Henderson { 27950faef01bSRichard Henderson tcg_gen_ext32u_tl(cpu_y, src); 27960faef01bSRichard Henderson } 27970faef01bSRichard Henderson 27980faef01bSRichard Henderson TRANS(WRY, ALL, do_wr_special, a, true, do_wry) 27990faef01bSRichard Henderson 28000faef01bSRichard Henderson static void do_wrccr(DisasContext *dc, TCGv src) 28010faef01bSRichard Henderson { 28020faef01bSRichard Henderson gen_helper_wrccr(tcg_env, src); 28030faef01bSRichard Henderson } 28040faef01bSRichard Henderson 28050faef01bSRichard Henderson TRANS(WRCCR, 64, do_wr_special, a, true, do_wrccr) 28060faef01bSRichard Henderson 28070faef01bSRichard Henderson static void do_wrasi(DisasContext *dc, TCGv src) 28080faef01bSRichard Henderson { 28090faef01bSRichard Henderson TCGv tmp = tcg_temp_new(); 28100faef01bSRichard Henderson 28110faef01bSRichard Henderson tcg_gen_ext8u_tl(tmp, src); 28120faef01bSRichard Henderson tcg_gen_st32_tl(tmp, tcg_env, env64_field_offsetof(asi)); 28130faef01bSRichard Henderson /* End TB to notice changed ASI. */ 28140faef01bSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 28150faef01bSRichard Henderson } 28160faef01bSRichard Henderson 28170faef01bSRichard Henderson TRANS(WRASI, 64, do_wr_special, a, true, do_wrasi) 28180faef01bSRichard Henderson 28190faef01bSRichard Henderson static void do_wrfprs(DisasContext *dc, TCGv src) 28200faef01bSRichard Henderson { 28210faef01bSRichard Henderson #ifdef TARGET_SPARC64 28220faef01bSRichard Henderson tcg_gen_trunc_tl_i32(cpu_fprs, src); 28230faef01bSRichard Henderson dc->fprs_dirty = 0; 28240faef01bSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 28250faef01bSRichard Henderson #else 28260faef01bSRichard Henderson qemu_build_not_reached(); 28270faef01bSRichard Henderson #endif 28280faef01bSRichard Henderson } 28290faef01bSRichard Henderson 28300faef01bSRichard Henderson TRANS(WRFPRS, 64, do_wr_special, a, true, do_wrfprs) 28310faef01bSRichard Henderson 28320faef01bSRichard Henderson static void do_wrgsr(DisasContext *dc, TCGv src) 28330faef01bSRichard Henderson { 28340faef01bSRichard Henderson gen_trap_ifnofpu(dc); 28350faef01bSRichard Henderson tcg_gen_mov_tl(cpu_gsr, src); 28360faef01bSRichard Henderson } 28370faef01bSRichard Henderson 28380faef01bSRichard Henderson TRANS(WRGSR, 64, do_wr_special, a, true, do_wrgsr) 28390faef01bSRichard Henderson 28400faef01bSRichard Henderson static void do_wrsoftint_set(DisasContext *dc, TCGv src) 28410faef01bSRichard Henderson { 28420faef01bSRichard Henderson gen_helper_set_softint(tcg_env, src); 28430faef01bSRichard Henderson } 28440faef01bSRichard Henderson 28450faef01bSRichard Henderson TRANS(WRSOFTINT_SET, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_set) 28460faef01bSRichard Henderson 28470faef01bSRichard Henderson static void do_wrsoftint_clr(DisasContext *dc, TCGv src) 28480faef01bSRichard Henderson { 28490faef01bSRichard Henderson gen_helper_clear_softint(tcg_env, src); 28500faef01bSRichard Henderson } 28510faef01bSRichard Henderson 28520faef01bSRichard Henderson TRANS(WRSOFTINT_CLR, 64, do_wr_special, a, supervisor(dc), do_wrsoftint_clr) 28530faef01bSRichard Henderson 28540faef01bSRichard Henderson static void do_wrsoftint(DisasContext *dc, TCGv src) 28550faef01bSRichard Henderson { 28560faef01bSRichard Henderson gen_helper_write_softint(tcg_env, src); 28570faef01bSRichard Henderson } 28580faef01bSRichard Henderson 28590faef01bSRichard Henderson TRANS(WRSOFTINT, 64, do_wr_special, a, supervisor(dc), do_wrsoftint) 28600faef01bSRichard Henderson 28610faef01bSRichard Henderson static void do_wrtick_cmpr(DisasContext *dc, TCGv src) 28620faef01bSRichard Henderson { 28630faef01bSRichard Henderson TCGv_ptr r_tickptr = tcg_temp_new_ptr(); 28640faef01bSRichard Henderson 2865577efa45SRichard Henderson tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(tick_cmpr)); 2866577efa45SRichard Henderson tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick)); 28670faef01bSRichard Henderson translator_io_start(&dc->base); 2868577efa45SRichard Henderson gen_helper_tick_set_limit(r_tickptr, src); 28690faef01bSRichard Henderson /* End TB to handle timer interrupt */ 28700faef01bSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 28710faef01bSRichard Henderson } 28720faef01bSRichard Henderson 28730faef01bSRichard Henderson TRANS(WRTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrtick_cmpr) 28740faef01bSRichard Henderson 28750faef01bSRichard Henderson static void do_wrstick(DisasContext *dc, TCGv src) 28760faef01bSRichard Henderson { 28770faef01bSRichard Henderson #ifdef TARGET_SPARC64 28780faef01bSRichard Henderson TCGv_ptr r_tickptr = tcg_temp_new_ptr(); 28790faef01bSRichard Henderson 28800faef01bSRichard Henderson tcg_gen_ld_ptr(r_tickptr, tcg_env, offsetof(CPUSPARCState, stick)); 28810faef01bSRichard Henderson translator_io_start(&dc->base); 28820faef01bSRichard Henderson gen_helper_tick_set_count(r_tickptr, src); 28830faef01bSRichard Henderson /* End TB to handle timer interrupt */ 28840faef01bSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 28850faef01bSRichard Henderson #else 28860faef01bSRichard Henderson qemu_build_not_reached(); 28870faef01bSRichard Henderson #endif 28880faef01bSRichard Henderson } 28890faef01bSRichard Henderson 28900faef01bSRichard Henderson TRANS(WRSTICK, 64, do_wr_special, a, supervisor(dc), do_wrstick) 28910faef01bSRichard Henderson 28920faef01bSRichard Henderson static void do_wrstick_cmpr(DisasContext *dc, TCGv src) 28930faef01bSRichard Henderson { 28940faef01bSRichard Henderson TCGv_ptr r_tickptr = tcg_temp_new_ptr(); 28950faef01bSRichard Henderson 2896577efa45SRichard Henderson tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(stick_cmpr)); 2897577efa45SRichard Henderson tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(stick)); 28980faef01bSRichard Henderson translator_io_start(&dc->base); 2899577efa45SRichard Henderson gen_helper_tick_set_limit(r_tickptr, src); 29000faef01bSRichard Henderson /* End TB to handle timer interrupt */ 29010faef01bSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 29020faef01bSRichard Henderson } 29030faef01bSRichard Henderson 29040faef01bSRichard Henderson TRANS(WRSTICK_CMPR, 64, do_wr_special, a, supervisor(dc), do_wrstick_cmpr) 29050faef01bSRichard Henderson 29060faef01bSRichard Henderson static void do_wrpowerdown(DisasContext *dc, TCGv src) 29070faef01bSRichard Henderson { 290889527e3aSRichard Henderson finishing_insn(dc); 29090faef01bSRichard Henderson save_state(dc); 29100faef01bSRichard Henderson gen_helper_power_down(tcg_env); 29110faef01bSRichard Henderson } 29120faef01bSRichard Henderson 29130faef01bSRichard Henderson TRANS(WRPOWERDOWN, POWERDOWN, do_wr_special, a, supervisor(dc), do_wrpowerdown) 29140faef01bSRichard Henderson 291525524734SRichard Henderson static void do_wrpsr(DisasContext *dc, TCGv src) 291625524734SRichard Henderson { 291725524734SRichard Henderson gen_helper_wrpsr(tcg_env, src); 291825524734SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 291925524734SRichard Henderson } 292025524734SRichard Henderson 292125524734SRichard Henderson TRANS(WRPSR, 32, do_wr_special, a, supervisor(dc), do_wrpsr) 292225524734SRichard Henderson 29239422278eSRichard Henderson static void do_wrwim(DisasContext *dc, TCGv src) 29249422278eSRichard Henderson { 29259422278eSRichard Henderson target_ulong mask = MAKE_64BIT_MASK(0, dc->def->nwindows); 2926cd6269f7SRichard Henderson TCGv tmp = tcg_temp_new(); 2927cd6269f7SRichard Henderson 2928cd6269f7SRichard Henderson tcg_gen_andi_tl(tmp, src, mask); 2929cd6269f7SRichard Henderson tcg_gen_st_tl(tmp, tcg_env, env32_field_offsetof(wim)); 29309422278eSRichard Henderson } 29319422278eSRichard Henderson 29329422278eSRichard Henderson TRANS(WRWIM, 32, do_wr_special, a, supervisor(dc), do_wrwim) 29339422278eSRichard Henderson 29349422278eSRichard Henderson static void do_wrtpc(DisasContext *dc, TCGv src) 29359422278eSRichard Henderson { 29369422278eSRichard Henderson #ifdef TARGET_SPARC64 29379422278eSRichard Henderson TCGv_ptr r_tsptr = tcg_temp_new_ptr(); 29389422278eSRichard Henderson 29399422278eSRichard Henderson gen_load_trap_state_at_tl(r_tsptr); 29409422278eSRichard Henderson tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tpc)); 29419422278eSRichard Henderson #else 29429422278eSRichard Henderson qemu_build_not_reached(); 29439422278eSRichard Henderson #endif 29449422278eSRichard Henderson } 29459422278eSRichard Henderson 29469422278eSRichard Henderson TRANS(WRPR_tpc, 64, do_wr_special, a, supervisor(dc), do_wrtpc) 29479422278eSRichard Henderson 29489422278eSRichard Henderson static void do_wrtnpc(DisasContext *dc, TCGv src) 29499422278eSRichard Henderson { 29509422278eSRichard Henderson #ifdef TARGET_SPARC64 29519422278eSRichard Henderson TCGv_ptr r_tsptr = tcg_temp_new_ptr(); 29529422278eSRichard Henderson 29539422278eSRichard Henderson gen_load_trap_state_at_tl(r_tsptr); 29549422278eSRichard Henderson tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tnpc)); 29559422278eSRichard Henderson #else 29569422278eSRichard Henderson qemu_build_not_reached(); 29579422278eSRichard Henderson #endif 29589422278eSRichard Henderson } 29599422278eSRichard Henderson 29609422278eSRichard Henderson TRANS(WRPR_tnpc, 64, do_wr_special, a, supervisor(dc), do_wrtnpc) 29619422278eSRichard Henderson 29629422278eSRichard Henderson static void do_wrtstate(DisasContext *dc, TCGv src) 29639422278eSRichard Henderson { 29649422278eSRichard Henderson #ifdef TARGET_SPARC64 29659422278eSRichard Henderson TCGv_ptr r_tsptr = tcg_temp_new_ptr(); 29669422278eSRichard Henderson 29679422278eSRichard Henderson gen_load_trap_state_at_tl(r_tsptr); 29689422278eSRichard Henderson tcg_gen_st_tl(src, r_tsptr, offsetof(trap_state, tstate)); 29699422278eSRichard Henderson #else 29709422278eSRichard Henderson qemu_build_not_reached(); 29719422278eSRichard Henderson #endif 29729422278eSRichard Henderson } 29739422278eSRichard Henderson 29749422278eSRichard Henderson TRANS(WRPR_tstate, 64, do_wr_special, a, supervisor(dc), do_wrtstate) 29759422278eSRichard Henderson 29769422278eSRichard Henderson static void do_wrtt(DisasContext *dc, TCGv src) 29779422278eSRichard Henderson { 29789422278eSRichard Henderson #ifdef TARGET_SPARC64 29799422278eSRichard Henderson TCGv_ptr r_tsptr = tcg_temp_new_ptr(); 29809422278eSRichard Henderson 29819422278eSRichard Henderson gen_load_trap_state_at_tl(r_tsptr); 29829422278eSRichard Henderson tcg_gen_st32_tl(src, r_tsptr, offsetof(trap_state, tt)); 29839422278eSRichard Henderson #else 29849422278eSRichard Henderson qemu_build_not_reached(); 29859422278eSRichard Henderson #endif 29869422278eSRichard Henderson } 29879422278eSRichard Henderson 29889422278eSRichard Henderson TRANS(WRPR_tt, 64, do_wr_special, a, supervisor(dc), do_wrtt) 29899422278eSRichard Henderson 29909422278eSRichard Henderson static void do_wrtick(DisasContext *dc, TCGv src) 29919422278eSRichard Henderson { 29929422278eSRichard Henderson TCGv_ptr r_tickptr = tcg_temp_new_ptr(); 29939422278eSRichard Henderson 29949422278eSRichard Henderson tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(tick)); 29959422278eSRichard Henderson translator_io_start(&dc->base); 29969422278eSRichard Henderson gen_helper_tick_set_count(r_tickptr, src); 29979422278eSRichard Henderson /* End TB to handle timer interrupt */ 29989422278eSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 29999422278eSRichard Henderson } 30009422278eSRichard Henderson 30019422278eSRichard Henderson TRANS(WRPR_tick, 64, do_wr_special, a, supervisor(dc), do_wrtick) 30029422278eSRichard Henderson 30039422278eSRichard Henderson static void do_wrtba(DisasContext *dc, TCGv src) 30049422278eSRichard Henderson { 30059422278eSRichard Henderson tcg_gen_mov_tl(cpu_tbr, src); 30069422278eSRichard Henderson } 30079422278eSRichard Henderson 30089422278eSRichard Henderson TRANS(WRPR_tba, 64, do_wr_special, a, supervisor(dc), do_wrtba) 30099422278eSRichard Henderson 30109422278eSRichard Henderson static void do_wrpstate(DisasContext *dc, TCGv src) 30119422278eSRichard Henderson { 30129422278eSRichard Henderson save_state(dc); 30139422278eSRichard Henderson if (translator_io_start(&dc->base)) { 30149422278eSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 30159422278eSRichard Henderson } 30169422278eSRichard Henderson gen_helper_wrpstate(tcg_env, src); 30179422278eSRichard Henderson dc->npc = DYNAMIC_PC; 30189422278eSRichard Henderson } 30199422278eSRichard Henderson 30209422278eSRichard Henderson TRANS(WRPR_pstate, 64, do_wr_special, a, supervisor(dc), do_wrpstate) 30219422278eSRichard Henderson 30229422278eSRichard Henderson static void do_wrtl(DisasContext *dc, TCGv src) 30239422278eSRichard Henderson { 30249422278eSRichard Henderson save_state(dc); 30259422278eSRichard Henderson tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(tl)); 30269422278eSRichard Henderson dc->npc = DYNAMIC_PC; 30279422278eSRichard Henderson } 30289422278eSRichard Henderson 30299422278eSRichard Henderson TRANS(WRPR_tl, 64, do_wr_special, a, supervisor(dc), do_wrtl) 30309422278eSRichard Henderson 30319422278eSRichard Henderson static void do_wrpil(DisasContext *dc, TCGv src) 30329422278eSRichard Henderson { 30339422278eSRichard Henderson if (translator_io_start(&dc->base)) { 30349422278eSRichard Henderson dc->base.is_jmp = DISAS_EXIT; 30359422278eSRichard Henderson } 30369422278eSRichard Henderson gen_helper_wrpil(tcg_env, src); 30379422278eSRichard Henderson } 30389422278eSRichard Henderson 30399422278eSRichard Henderson TRANS(WRPR_pil, 64, do_wr_special, a, supervisor(dc), do_wrpil) 30409422278eSRichard Henderson 30419422278eSRichard Henderson static void do_wrcwp(DisasContext *dc, TCGv src) 30429422278eSRichard Henderson { 30439422278eSRichard Henderson gen_helper_wrcwp(tcg_env, src); 30449422278eSRichard Henderson } 30459422278eSRichard Henderson 30469422278eSRichard Henderson TRANS(WRPR_cwp, 64, do_wr_special, a, supervisor(dc), do_wrcwp) 30479422278eSRichard Henderson 30489422278eSRichard Henderson static void do_wrcansave(DisasContext *dc, TCGv src) 30499422278eSRichard Henderson { 30509422278eSRichard Henderson tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(cansave)); 30519422278eSRichard Henderson } 30529422278eSRichard Henderson 30539422278eSRichard Henderson TRANS(WRPR_cansave, 64, do_wr_special, a, supervisor(dc), do_wrcansave) 30549422278eSRichard Henderson 30559422278eSRichard Henderson static void do_wrcanrestore(DisasContext *dc, TCGv src) 30569422278eSRichard Henderson { 30579422278eSRichard Henderson tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(canrestore)); 30589422278eSRichard Henderson } 30599422278eSRichard Henderson 30609422278eSRichard Henderson TRANS(WRPR_canrestore, 64, do_wr_special, a, supervisor(dc), do_wrcanrestore) 30619422278eSRichard Henderson 30629422278eSRichard Henderson static void do_wrcleanwin(DisasContext *dc, TCGv src) 30639422278eSRichard Henderson { 30649422278eSRichard Henderson tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(cleanwin)); 30659422278eSRichard Henderson } 30669422278eSRichard Henderson 30679422278eSRichard Henderson TRANS(WRPR_cleanwin, 64, do_wr_special, a, supervisor(dc), do_wrcleanwin) 30689422278eSRichard Henderson 30699422278eSRichard Henderson static void do_wrotherwin(DisasContext *dc, TCGv src) 30709422278eSRichard Henderson { 30719422278eSRichard Henderson tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(otherwin)); 30729422278eSRichard Henderson } 30739422278eSRichard Henderson 30749422278eSRichard Henderson TRANS(WRPR_otherwin, 64, do_wr_special, a, supervisor(dc), do_wrotherwin) 30759422278eSRichard Henderson 30769422278eSRichard Henderson static void do_wrwstate(DisasContext *dc, TCGv src) 30779422278eSRichard Henderson { 30789422278eSRichard Henderson tcg_gen_st32_tl(src, tcg_env, env64_field_offsetof(wstate)); 30799422278eSRichard Henderson } 30809422278eSRichard Henderson 30819422278eSRichard Henderson TRANS(WRPR_wstate, 64, do_wr_special, a, supervisor(dc), do_wrwstate) 30829422278eSRichard Henderson 30839422278eSRichard Henderson static void do_wrgl(DisasContext *dc, TCGv src) 30849422278eSRichard Henderson { 30859422278eSRichard Henderson gen_helper_wrgl(tcg_env, src); 30869422278eSRichard Henderson } 30879422278eSRichard Henderson 30889422278eSRichard Henderson TRANS(WRPR_gl, GL, do_wr_special, a, supervisor(dc), do_wrgl) 30899422278eSRichard Henderson 30909422278eSRichard Henderson /* UA2005 strand status */ 30919422278eSRichard Henderson static void do_wrssr(DisasContext *dc, TCGv src) 30929422278eSRichard Henderson { 30932da789deSRichard Henderson tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(ssr)); 30949422278eSRichard Henderson } 30959422278eSRichard Henderson 30969422278eSRichard Henderson TRANS(WRPR_strand_status, HYPV, do_wr_special, a, hypervisor(dc), do_wrssr) 30979422278eSRichard Henderson 3098bb97f2f5SRichard Henderson TRANS(WRTBR, 32, do_wr_special, a, supervisor(dc), do_wrtba) 3099bb97f2f5SRichard Henderson 3100bb97f2f5SRichard Henderson static void do_wrhpstate(DisasContext *dc, TCGv src) 3101bb97f2f5SRichard Henderson { 3102bb97f2f5SRichard Henderson tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hpstate)); 3103bb97f2f5SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 3104bb97f2f5SRichard Henderson } 3105bb97f2f5SRichard Henderson 3106bb97f2f5SRichard Henderson TRANS(WRHPR_hpstate, HYPV, do_wr_special, a, hypervisor(dc), do_wrhpstate) 3107bb97f2f5SRichard Henderson 3108bb97f2f5SRichard Henderson static void do_wrhtstate(DisasContext *dc, TCGv src) 3109bb97f2f5SRichard Henderson { 3110bb97f2f5SRichard Henderson TCGv_i32 tl = tcg_temp_new_i32(); 3111bb97f2f5SRichard Henderson TCGv_ptr tp = tcg_temp_new_ptr(); 3112bb97f2f5SRichard Henderson 3113bb97f2f5SRichard Henderson tcg_gen_ld_i32(tl, tcg_env, env64_field_offsetof(tl)); 3114bb97f2f5SRichard Henderson tcg_gen_andi_i32(tl, tl, MAXTL_MASK); 3115bb97f2f5SRichard Henderson tcg_gen_shli_i32(tl, tl, 3); 3116bb97f2f5SRichard Henderson tcg_gen_ext_i32_ptr(tp, tl); 3117bb97f2f5SRichard Henderson tcg_gen_add_ptr(tp, tp, tcg_env); 3118bb97f2f5SRichard Henderson 3119bb97f2f5SRichard Henderson tcg_gen_st_tl(src, tp, env64_field_offsetof(htstate)); 3120bb97f2f5SRichard Henderson } 3121bb97f2f5SRichard Henderson 3122bb97f2f5SRichard Henderson TRANS(WRHPR_htstate, HYPV, do_wr_special, a, hypervisor(dc), do_wrhtstate) 3123bb97f2f5SRichard Henderson 3124bb97f2f5SRichard Henderson static void do_wrhintp(DisasContext *dc, TCGv src) 3125bb97f2f5SRichard Henderson { 31262da789deSRichard Henderson tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hintp)); 3127bb97f2f5SRichard Henderson } 3128bb97f2f5SRichard Henderson 3129bb97f2f5SRichard Henderson TRANS(WRHPR_hintp, HYPV, do_wr_special, a, hypervisor(dc), do_wrhintp) 3130bb97f2f5SRichard Henderson 3131bb97f2f5SRichard Henderson static void do_wrhtba(DisasContext *dc, TCGv src) 3132bb97f2f5SRichard Henderson { 31332da789deSRichard Henderson tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(htba)); 3134bb97f2f5SRichard Henderson } 3135bb97f2f5SRichard Henderson 3136bb97f2f5SRichard Henderson TRANS(WRHPR_htba, HYPV, do_wr_special, a, hypervisor(dc), do_wrhtba) 3137bb97f2f5SRichard Henderson 3138bb97f2f5SRichard Henderson static void do_wrhstick_cmpr(DisasContext *dc, TCGv src) 3139bb97f2f5SRichard Henderson { 3140bb97f2f5SRichard Henderson TCGv_ptr r_tickptr = tcg_temp_new_ptr(); 3141bb97f2f5SRichard Henderson 3142577efa45SRichard Henderson tcg_gen_st_tl(src, tcg_env, env64_field_offsetof(hstick_cmpr)); 3143bb97f2f5SRichard Henderson tcg_gen_ld_ptr(r_tickptr, tcg_env, env64_field_offsetof(hstick)); 3144bb97f2f5SRichard Henderson translator_io_start(&dc->base); 3145577efa45SRichard Henderson gen_helper_tick_set_limit(r_tickptr, src); 3146bb97f2f5SRichard Henderson /* End TB to handle timer interrupt */ 3147bb97f2f5SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 3148bb97f2f5SRichard Henderson } 3149bb97f2f5SRichard Henderson 3150bb97f2f5SRichard Henderson TRANS(WRHPR_hstick_cmpr, HYPV, do_wr_special, a, hypervisor(dc), 3151bb97f2f5SRichard Henderson do_wrhstick_cmpr) 3152bb97f2f5SRichard Henderson 315325524734SRichard Henderson static bool do_saved_restored(DisasContext *dc, bool saved) 315425524734SRichard Henderson { 315525524734SRichard Henderson if (!supervisor(dc)) { 315625524734SRichard Henderson return raise_priv(dc); 315725524734SRichard Henderson } 315825524734SRichard Henderson if (saved) { 315925524734SRichard Henderson gen_helper_saved(tcg_env); 316025524734SRichard Henderson } else { 316125524734SRichard Henderson gen_helper_restored(tcg_env); 316225524734SRichard Henderson } 316325524734SRichard Henderson return advance_pc(dc); 316425524734SRichard Henderson } 316525524734SRichard Henderson 316625524734SRichard Henderson TRANS(SAVED, 64, do_saved_restored, true) 316725524734SRichard Henderson TRANS(RESTORED, 64, do_saved_restored, false) 316825524734SRichard Henderson 3169d3825800SRichard Henderson static bool trans_NOP(DisasContext *dc, arg_NOP *a) 3170d3825800SRichard Henderson { 3171d3825800SRichard Henderson return advance_pc(dc); 3172d3825800SRichard Henderson } 3173d3825800SRichard Henderson 31740faef01bSRichard Henderson /* 31750faef01bSRichard Henderson * TODO: Need a feature bit for sparcv8. 31760faef01bSRichard Henderson * In the meantime, treat all 32-bit cpus like sparcv7. 31770faef01bSRichard Henderson */ 31785458fd31SRichard Henderson TRANS(NOP_v7, 32, trans_NOP, a) 31795458fd31SRichard Henderson TRANS(NOP_v9, 64, trans_NOP, a) 31800faef01bSRichard Henderson 3181b597eedcSRichard Henderson static bool do_arith_int(DisasContext *dc, arg_r_r_ri_cc *a, 3182428881deSRichard Henderson void (*func)(TCGv, TCGv, TCGv), 31832a45b736SRichard Henderson void (*funci)(TCGv, TCGv, target_long), 31842a45b736SRichard Henderson bool logic_cc) 3185428881deSRichard Henderson { 3186428881deSRichard Henderson TCGv dst, src1; 3187428881deSRichard Henderson 3188428881deSRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 3189428881deSRichard Henderson if (!a->imm && a->rs2_or_imm & ~0x1f) { 3190428881deSRichard Henderson return false; 3191428881deSRichard Henderson } 3192428881deSRichard Henderson 31932a45b736SRichard Henderson if (logic_cc) { 31942a45b736SRichard Henderson dst = cpu_cc_N; 3195428881deSRichard Henderson } else { 3196428881deSRichard Henderson dst = gen_dest_gpr(dc, a->rd); 3197428881deSRichard Henderson } 3198428881deSRichard Henderson src1 = gen_load_gpr(dc, a->rs1); 3199428881deSRichard Henderson 3200428881deSRichard Henderson if (a->imm || a->rs2_or_imm == 0) { 3201428881deSRichard Henderson if (funci) { 3202428881deSRichard Henderson funci(dst, src1, a->rs2_or_imm); 3203428881deSRichard Henderson } else { 3204428881deSRichard Henderson func(dst, src1, tcg_constant_tl(a->rs2_or_imm)); 3205428881deSRichard Henderson } 3206428881deSRichard Henderson } else { 3207428881deSRichard Henderson func(dst, src1, cpu_regs[a->rs2_or_imm]); 3208428881deSRichard Henderson } 32092a45b736SRichard Henderson 32102a45b736SRichard Henderson if (logic_cc) { 32112a45b736SRichard Henderson if (TARGET_LONG_BITS == 64) { 32122a45b736SRichard Henderson tcg_gen_mov_tl(cpu_icc_Z, cpu_cc_N); 32132a45b736SRichard Henderson tcg_gen_movi_tl(cpu_icc_C, 0); 32142a45b736SRichard Henderson } 32152a45b736SRichard Henderson tcg_gen_mov_tl(cpu_cc_Z, cpu_cc_N); 32162a45b736SRichard Henderson tcg_gen_movi_tl(cpu_cc_C, 0); 32172a45b736SRichard Henderson tcg_gen_movi_tl(cpu_cc_V, 0); 32182a45b736SRichard Henderson } 32192a45b736SRichard Henderson 3220428881deSRichard Henderson gen_store_gpr(dc, a->rd, dst); 3221428881deSRichard Henderson return advance_pc(dc); 3222428881deSRichard Henderson } 3223428881deSRichard Henderson 3224b597eedcSRichard Henderson static bool do_arith(DisasContext *dc, arg_r_r_ri_cc *a, 3225428881deSRichard Henderson void (*func)(TCGv, TCGv, TCGv), 3226428881deSRichard Henderson void (*funci)(TCGv, TCGv, target_long), 3227428881deSRichard Henderson void (*func_cc)(TCGv, TCGv, TCGv)) 3228428881deSRichard Henderson { 3229428881deSRichard Henderson if (a->cc) { 3230b597eedcSRichard Henderson return do_arith_int(dc, a, func_cc, NULL, false); 3231428881deSRichard Henderson } 3232b597eedcSRichard Henderson return do_arith_int(dc, a, func, funci, false); 3233428881deSRichard Henderson } 3234428881deSRichard Henderson 3235428881deSRichard Henderson static bool do_logic(DisasContext *dc, arg_r_r_ri_cc *a, 3236428881deSRichard Henderson void (*func)(TCGv, TCGv, TCGv), 3237428881deSRichard Henderson void (*funci)(TCGv, TCGv, target_long)) 3238428881deSRichard Henderson { 3239b597eedcSRichard Henderson return do_arith_int(dc, a, func, funci, a->cc); 3240428881deSRichard Henderson } 3241428881deSRichard Henderson 3242b597eedcSRichard Henderson TRANS(ADD, ALL, do_arith, a, tcg_gen_add_tl, tcg_gen_addi_tl, gen_op_addcc) 3243b597eedcSRichard Henderson TRANS(SUB, ALL, do_arith, a, tcg_gen_sub_tl, tcg_gen_subi_tl, gen_op_subcc) 3244b597eedcSRichard Henderson TRANS(ADDC, ALL, do_arith, a, gen_op_addc, NULL, gen_op_addccc) 3245b597eedcSRichard Henderson TRANS(SUBC, ALL, do_arith, a, gen_op_subc, NULL, gen_op_subccc) 3246428881deSRichard Henderson 3247b597eedcSRichard Henderson TRANS(TADDcc, ALL, do_arith, a, NULL, NULL, gen_op_taddcc) 3248b597eedcSRichard Henderson TRANS(TSUBcc, ALL, do_arith, a, NULL, NULL, gen_op_tsubcc) 3249b597eedcSRichard Henderson TRANS(TADDccTV, ALL, do_arith, a, NULL, NULL, gen_op_taddcctv) 3250b597eedcSRichard Henderson TRANS(TSUBccTV, ALL, do_arith, a, NULL, NULL, gen_op_tsubcctv) 3251a9aba13dSRichard Henderson 3252428881deSRichard Henderson TRANS(AND, ALL, do_logic, a, tcg_gen_and_tl, tcg_gen_andi_tl) 3253428881deSRichard Henderson TRANS(XOR, ALL, do_logic, a, tcg_gen_xor_tl, tcg_gen_xori_tl) 3254428881deSRichard Henderson TRANS(ANDN, ALL, do_logic, a, tcg_gen_andc_tl, NULL) 3255428881deSRichard Henderson TRANS(ORN, ALL, do_logic, a, tcg_gen_orc_tl, NULL) 3256428881deSRichard Henderson TRANS(XORN, ALL, do_logic, a, tcg_gen_eqv_tl, NULL) 3257428881deSRichard Henderson 3258b597eedcSRichard Henderson TRANS(MULX, 64, do_arith, a, tcg_gen_mul_tl, tcg_gen_muli_tl, NULL) 3259b5372650SRichard Henderson TRANS(UMUL, MUL, do_logic, a, gen_op_umul, NULL) 3260b5372650SRichard Henderson TRANS(SMUL, MUL, do_logic, a, gen_op_smul, NULL) 3261b597eedcSRichard Henderson TRANS(MULScc, ALL, do_arith, a, NULL, NULL, gen_op_mulscc) 326222188d7dSRichard Henderson 32633a6b8de3SRichard Henderson TRANS(UDIVcc, DIV, do_arith, a, NULL, NULL, gen_op_udivcc) 3264b597eedcSRichard Henderson TRANS(SDIV, DIV, do_arith, a, gen_op_sdiv, NULL, gen_op_sdivcc) 32654ee85ea9SRichard Henderson 32669c6ec5bcSRichard Henderson /* TODO: Should have feature bit -- comes in with UltraSparc T2. */ 3267b597eedcSRichard Henderson TRANS(POPC, 64, do_arith, a, gen_op_popc, NULL, NULL) 32689c6ec5bcSRichard Henderson 3269428881deSRichard Henderson static bool trans_OR(DisasContext *dc, arg_r_r_ri_cc *a) 3270428881deSRichard Henderson { 3271428881deSRichard Henderson /* OR with %g0 is the canonical alias for MOV. */ 3272428881deSRichard Henderson if (!a->cc && a->rs1 == 0) { 3273428881deSRichard Henderson if (a->imm || a->rs2_or_imm == 0) { 3274428881deSRichard Henderson gen_store_gpr(dc, a->rd, tcg_constant_tl(a->rs2_or_imm)); 3275428881deSRichard Henderson } else if (a->rs2_or_imm & ~0x1f) { 3276428881deSRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 3277428881deSRichard Henderson return false; 3278428881deSRichard Henderson } else { 3279428881deSRichard Henderson gen_store_gpr(dc, a->rd, cpu_regs[a->rs2_or_imm]); 3280428881deSRichard Henderson } 3281428881deSRichard Henderson return advance_pc(dc); 3282428881deSRichard Henderson } 3283428881deSRichard Henderson return do_logic(dc, a, tcg_gen_or_tl, tcg_gen_ori_tl); 3284428881deSRichard Henderson } 3285428881deSRichard Henderson 32863a6b8de3SRichard Henderson static bool trans_UDIV(DisasContext *dc, arg_r_r_ri *a) 32873a6b8de3SRichard Henderson { 32883a6b8de3SRichard Henderson TCGv_i64 t1, t2; 32893a6b8de3SRichard Henderson TCGv dst; 32903a6b8de3SRichard Henderson 32913a6b8de3SRichard Henderson if (!avail_DIV(dc)) { 32923a6b8de3SRichard Henderson return false; 32933a6b8de3SRichard Henderson } 32943a6b8de3SRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 32953a6b8de3SRichard Henderson if (!a->imm && a->rs2_or_imm & ~0x1f) { 32963a6b8de3SRichard Henderson return false; 32973a6b8de3SRichard Henderson } 32983a6b8de3SRichard Henderson 32993a6b8de3SRichard Henderson if (unlikely(a->rs2_or_imm == 0)) { 33003a6b8de3SRichard Henderson gen_exception(dc, TT_DIV_ZERO); 33013a6b8de3SRichard Henderson return true; 33023a6b8de3SRichard Henderson } 33033a6b8de3SRichard Henderson 33043a6b8de3SRichard Henderson if (a->imm) { 33053a6b8de3SRichard Henderson t2 = tcg_constant_i64((uint32_t)a->rs2_or_imm); 33063a6b8de3SRichard Henderson } else { 33073a6b8de3SRichard Henderson TCGLabel *lab; 33083a6b8de3SRichard Henderson TCGv_i32 n2; 33093a6b8de3SRichard Henderson 33103a6b8de3SRichard Henderson finishing_insn(dc); 33113a6b8de3SRichard Henderson flush_cond(dc); 33123a6b8de3SRichard Henderson 33133a6b8de3SRichard Henderson n2 = tcg_temp_new_i32(); 33143a6b8de3SRichard Henderson tcg_gen_trunc_tl_i32(n2, cpu_regs[a->rs2_or_imm]); 33153a6b8de3SRichard Henderson 33163a6b8de3SRichard Henderson lab = delay_exception(dc, TT_DIV_ZERO); 33173a6b8de3SRichard Henderson tcg_gen_brcondi_i32(TCG_COND_EQ, n2, 0, lab); 33183a6b8de3SRichard Henderson 33193a6b8de3SRichard Henderson t2 = tcg_temp_new_i64(); 33203a6b8de3SRichard Henderson #ifdef TARGET_SPARC64 33213a6b8de3SRichard Henderson tcg_gen_ext32u_i64(t2, cpu_regs[a->rs2_or_imm]); 33223a6b8de3SRichard Henderson #else 33233a6b8de3SRichard Henderson tcg_gen_extu_i32_i64(t2, cpu_regs[a->rs2_or_imm]); 33243a6b8de3SRichard Henderson #endif 33253a6b8de3SRichard Henderson } 33263a6b8de3SRichard Henderson 33273a6b8de3SRichard Henderson t1 = tcg_temp_new_i64(); 33283a6b8de3SRichard Henderson tcg_gen_concat_tl_i64(t1, gen_load_gpr(dc, a->rs1), cpu_y); 33293a6b8de3SRichard Henderson 33303a6b8de3SRichard Henderson tcg_gen_divu_i64(t1, t1, t2); 33313a6b8de3SRichard Henderson tcg_gen_umin_i64(t1, t1, tcg_constant_i64(UINT32_MAX)); 33323a6b8de3SRichard Henderson 33333a6b8de3SRichard Henderson dst = gen_dest_gpr(dc, a->rd); 33343a6b8de3SRichard Henderson tcg_gen_trunc_i64_tl(dst, t1); 33353a6b8de3SRichard Henderson gen_store_gpr(dc, a->rd, dst); 33363a6b8de3SRichard Henderson return advance_pc(dc); 33373a6b8de3SRichard Henderson } 33383a6b8de3SRichard Henderson 3339f3141174SRichard Henderson static bool trans_UDIVX(DisasContext *dc, arg_r_r_ri *a) 3340f3141174SRichard Henderson { 3341f3141174SRichard Henderson TCGv dst, src1, src2; 3342f3141174SRichard Henderson 3343f3141174SRichard Henderson if (!avail_64(dc)) { 3344f3141174SRichard Henderson return false; 3345f3141174SRichard Henderson } 3346f3141174SRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 3347f3141174SRichard Henderson if (!a->imm && a->rs2_or_imm & ~0x1f) { 3348f3141174SRichard Henderson return false; 3349f3141174SRichard Henderson } 3350f3141174SRichard Henderson 3351f3141174SRichard Henderson if (unlikely(a->rs2_or_imm == 0)) { 3352f3141174SRichard Henderson gen_exception(dc, TT_DIV_ZERO); 3353f3141174SRichard Henderson return true; 3354f3141174SRichard Henderson } 3355f3141174SRichard Henderson 3356f3141174SRichard Henderson if (a->imm) { 3357f3141174SRichard Henderson src2 = tcg_constant_tl(a->rs2_or_imm); 3358f3141174SRichard Henderson } else { 3359f3141174SRichard Henderson TCGLabel *lab; 3360f3141174SRichard Henderson 3361f3141174SRichard Henderson finishing_insn(dc); 3362f3141174SRichard Henderson flush_cond(dc); 3363f3141174SRichard Henderson 3364f3141174SRichard Henderson lab = delay_exception(dc, TT_DIV_ZERO); 3365f3141174SRichard Henderson src2 = cpu_regs[a->rs2_or_imm]; 3366f3141174SRichard Henderson tcg_gen_brcondi_tl(TCG_COND_EQ, src2, 0, lab); 3367f3141174SRichard Henderson } 3368f3141174SRichard Henderson 3369f3141174SRichard Henderson dst = gen_dest_gpr(dc, a->rd); 3370f3141174SRichard Henderson src1 = gen_load_gpr(dc, a->rs1); 3371f3141174SRichard Henderson 3372f3141174SRichard Henderson tcg_gen_divu_tl(dst, src1, src2); 3373f3141174SRichard Henderson gen_store_gpr(dc, a->rd, dst); 3374f3141174SRichard Henderson return advance_pc(dc); 3375f3141174SRichard Henderson } 3376f3141174SRichard Henderson 3377f3141174SRichard Henderson static bool trans_SDIVX(DisasContext *dc, arg_r_r_ri *a) 3378f3141174SRichard Henderson { 3379f3141174SRichard Henderson TCGv dst, src1, src2; 3380f3141174SRichard Henderson 3381f3141174SRichard Henderson if (!avail_64(dc)) { 3382f3141174SRichard Henderson return false; 3383f3141174SRichard Henderson } 3384f3141174SRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 3385f3141174SRichard Henderson if (!a->imm && a->rs2_or_imm & ~0x1f) { 3386f3141174SRichard Henderson return false; 3387f3141174SRichard Henderson } 3388f3141174SRichard Henderson 3389f3141174SRichard Henderson if (unlikely(a->rs2_or_imm == 0)) { 3390f3141174SRichard Henderson gen_exception(dc, TT_DIV_ZERO); 3391f3141174SRichard Henderson return true; 3392f3141174SRichard Henderson } 3393f3141174SRichard Henderson 3394f3141174SRichard Henderson dst = gen_dest_gpr(dc, a->rd); 3395f3141174SRichard Henderson src1 = gen_load_gpr(dc, a->rs1); 3396f3141174SRichard Henderson 3397f3141174SRichard Henderson if (a->imm) { 3398f3141174SRichard Henderson if (unlikely(a->rs2_or_imm == -1)) { 3399f3141174SRichard Henderson tcg_gen_neg_tl(dst, src1); 3400f3141174SRichard Henderson gen_store_gpr(dc, a->rd, dst); 3401f3141174SRichard Henderson return advance_pc(dc); 3402f3141174SRichard Henderson } 3403f3141174SRichard Henderson src2 = tcg_constant_tl(a->rs2_or_imm); 3404f3141174SRichard Henderson } else { 3405f3141174SRichard Henderson TCGLabel *lab; 3406f3141174SRichard Henderson TCGv t1, t2; 3407f3141174SRichard Henderson 3408f3141174SRichard Henderson finishing_insn(dc); 3409f3141174SRichard Henderson flush_cond(dc); 3410f3141174SRichard Henderson 3411f3141174SRichard Henderson lab = delay_exception(dc, TT_DIV_ZERO); 3412f3141174SRichard Henderson src2 = cpu_regs[a->rs2_or_imm]; 3413f3141174SRichard Henderson tcg_gen_brcondi_tl(TCG_COND_EQ, src2, 0, lab); 3414f3141174SRichard Henderson 3415f3141174SRichard Henderson /* 3416f3141174SRichard Henderson * Need to avoid INT64_MIN / -1, which will trap on x86 host. 3417f3141174SRichard Henderson * Set SRC2 to 1 as a new divisor, to produce the correct result. 3418f3141174SRichard Henderson */ 3419f3141174SRichard Henderson t1 = tcg_temp_new(); 3420f3141174SRichard Henderson t2 = tcg_temp_new(); 3421f3141174SRichard Henderson tcg_gen_setcondi_tl(TCG_COND_EQ, t1, src1, (target_long)INT64_MIN); 3422f3141174SRichard Henderson tcg_gen_setcondi_tl(TCG_COND_EQ, t2, src2, -1); 3423f3141174SRichard Henderson tcg_gen_and_tl(t1, t1, t2); 3424f3141174SRichard Henderson tcg_gen_movcond_tl(TCG_COND_NE, t1, t1, tcg_constant_tl(0), 3425f3141174SRichard Henderson tcg_constant_tl(1), src2); 3426f3141174SRichard Henderson src2 = t1; 3427f3141174SRichard Henderson } 3428f3141174SRichard Henderson 3429f3141174SRichard Henderson tcg_gen_div_tl(dst, src1, src2); 3430f3141174SRichard Henderson gen_store_gpr(dc, a->rd, dst); 3431f3141174SRichard Henderson return advance_pc(dc); 3432f3141174SRichard Henderson } 3433f3141174SRichard Henderson 3434b88ce6f2SRichard Henderson static bool gen_edge(DisasContext *dc, arg_r_r_r *a, 3435b88ce6f2SRichard Henderson int width, bool cc, bool left) 3436b88ce6f2SRichard Henderson { 3437b88ce6f2SRichard Henderson TCGv dst, s1, s2, lo1, lo2; 3438b88ce6f2SRichard Henderson uint64_t amask, tabl, tabr; 3439b88ce6f2SRichard Henderson int shift, imask, omask; 3440b88ce6f2SRichard Henderson 3441b88ce6f2SRichard Henderson dst = gen_dest_gpr(dc, a->rd); 3442b88ce6f2SRichard Henderson s1 = gen_load_gpr(dc, a->rs1); 3443b88ce6f2SRichard Henderson s2 = gen_load_gpr(dc, a->rs2); 3444b88ce6f2SRichard Henderson 3445b88ce6f2SRichard Henderson if (cc) { 3446f828df74SRichard Henderson gen_op_subcc(cpu_cc_N, s1, s2); 3447b88ce6f2SRichard Henderson } 3448b88ce6f2SRichard Henderson 3449b88ce6f2SRichard Henderson /* 3450b88ce6f2SRichard Henderson * Theory of operation: there are two tables, left and right (not to 3451b88ce6f2SRichard Henderson * be confused with the left and right versions of the opcode). These 3452b88ce6f2SRichard Henderson * are indexed by the low 3 bits of the inputs. To make things "easy", 3453b88ce6f2SRichard Henderson * these tables are loaded into two constants, TABL and TABR below. 3454b88ce6f2SRichard Henderson * The operation index = (input & imask) << shift calculates the index 3455b88ce6f2SRichard Henderson * into the constant, while val = (table >> index) & omask calculates 3456b88ce6f2SRichard Henderson * the value we're looking for. 3457b88ce6f2SRichard Henderson */ 3458b88ce6f2SRichard Henderson switch (width) { 3459b88ce6f2SRichard Henderson case 8: 3460b88ce6f2SRichard Henderson imask = 0x7; 3461b88ce6f2SRichard Henderson shift = 3; 3462b88ce6f2SRichard Henderson omask = 0xff; 3463b88ce6f2SRichard Henderson if (left) { 3464b88ce6f2SRichard Henderson tabl = 0x80c0e0f0f8fcfeffULL; 3465b88ce6f2SRichard Henderson tabr = 0xff7f3f1f0f070301ULL; 3466b88ce6f2SRichard Henderson } else { 3467b88ce6f2SRichard Henderson tabl = 0x0103070f1f3f7fffULL; 3468b88ce6f2SRichard Henderson tabr = 0xfffefcf8f0e0c080ULL; 3469b88ce6f2SRichard Henderson } 3470b88ce6f2SRichard Henderson break; 3471b88ce6f2SRichard Henderson case 16: 3472b88ce6f2SRichard Henderson imask = 0x6; 3473b88ce6f2SRichard Henderson shift = 1; 3474b88ce6f2SRichard Henderson omask = 0xf; 3475b88ce6f2SRichard Henderson if (left) { 3476b88ce6f2SRichard Henderson tabl = 0x8cef; 3477b88ce6f2SRichard Henderson tabr = 0xf731; 3478b88ce6f2SRichard Henderson } else { 3479b88ce6f2SRichard Henderson tabl = 0x137f; 3480b88ce6f2SRichard Henderson tabr = 0xfec8; 3481b88ce6f2SRichard Henderson } 3482b88ce6f2SRichard Henderson break; 3483b88ce6f2SRichard Henderson case 32: 3484b88ce6f2SRichard Henderson imask = 0x4; 3485b88ce6f2SRichard Henderson shift = 0; 3486b88ce6f2SRichard Henderson omask = 0x3; 3487b88ce6f2SRichard Henderson if (left) { 3488b88ce6f2SRichard Henderson tabl = (2 << 2) | 3; 3489b88ce6f2SRichard Henderson tabr = (3 << 2) | 1; 3490b88ce6f2SRichard Henderson } else { 3491b88ce6f2SRichard Henderson tabl = (1 << 2) | 3; 3492b88ce6f2SRichard Henderson tabr = (3 << 2) | 2; 3493b88ce6f2SRichard Henderson } 3494b88ce6f2SRichard Henderson break; 3495b88ce6f2SRichard Henderson default: 3496b88ce6f2SRichard Henderson abort(); 3497b88ce6f2SRichard Henderson } 3498b88ce6f2SRichard Henderson 3499b88ce6f2SRichard Henderson lo1 = tcg_temp_new(); 3500b88ce6f2SRichard Henderson lo2 = tcg_temp_new(); 3501b88ce6f2SRichard Henderson tcg_gen_andi_tl(lo1, s1, imask); 3502b88ce6f2SRichard Henderson tcg_gen_andi_tl(lo2, s2, imask); 3503b88ce6f2SRichard Henderson tcg_gen_shli_tl(lo1, lo1, shift); 3504b88ce6f2SRichard Henderson tcg_gen_shli_tl(lo2, lo2, shift); 3505b88ce6f2SRichard Henderson 3506b88ce6f2SRichard Henderson tcg_gen_shr_tl(lo1, tcg_constant_tl(tabl), lo1); 3507b88ce6f2SRichard Henderson tcg_gen_shr_tl(lo2, tcg_constant_tl(tabr), lo2); 3508b88ce6f2SRichard Henderson tcg_gen_andi_tl(lo1, lo1, omask); 3509b88ce6f2SRichard Henderson tcg_gen_andi_tl(lo2, lo2, omask); 3510b88ce6f2SRichard Henderson 3511b88ce6f2SRichard Henderson amask = address_mask_i(dc, -8); 3512b88ce6f2SRichard Henderson tcg_gen_andi_tl(s1, s1, amask); 3513b88ce6f2SRichard Henderson tcg_gen_andi_tl(s2, s2, amask); 3514b88ce6f2SRichard Henderson 3515b88ce6f2SRichard Henderson /* Compute dst = (s1 == s2 ? lo1 : lo1 & lo2). */ 3516b88ce6f2SRichard Henderson tcg_gen_and_tl(lo2, lo2, lo1); 3517b88ce6f2SRichard Henderson tcg_gen_movcond_tl(TCG_COND_EQ, dst, s1, s2, lo1, lo2); 3518b88ce6f2SRichard Henderson 3519b88ce6f2SRichard Henderson gen_store_gpr(dc, a->rd, dst); 3520b88ce6f2SRichard Henderson return advance_pc(dc); 3521b88ce6f2SRichard Henderson } 3522b88ce6f2SRichard Henderson 3523b88ce6f2SRichard Henderson TRANS(EDGE8cc, VIS1, gen_edge, a, 8, 1, 0) 3524b88ce6f2SRichard Henderson TRANS(EDGE8Lcc, VIS1, gen_edge, a, 8, 1, 1) 3525b88ce6f2SRichard Henderson TRANS(EDGE16cc, VIS1, gen_edge, a, 16, 1, 0) 3526b88ce6f2SRichard Henderson TRANS(EDGE16Lcc, VIS1, gen_edge, a, 16, 1, 1) 3527b88ce6f2SRichard Henderson TRANS(EDGE32cc, VIS1, gen_edge, a, 32, 1, 0) 3528b88ce6f2SRichard Henderson TRANS(EDGE32Lcc, VIS1, gen_edge, a, 32, 1, 1) 3529b88ce6f2SRichard Henderson 3530b88ce6f2SRichard Henderson TRANS(EDGE8N, VIS2, gen_edge, a, 8, 0, 0) 3531b88ce6f2SRichard Henderson TRANS(EDGE8LN, VIS2, gen_edge, a, 8, 0, 1) 3532b88ce6f2SRichard Henderson TRANS(EDGE16N, VIS2, gen_edge, a, 16, 0, 0) 3533b88ce6f2SRichard Henderson TRANS(EDGE16LN, VIS2, gen_edge, a, 16, 0, 1) 3534b88ce6f2SRichard Henderson TRANS(EDGE32N, VIS2, gen_edge, a, 32, 0, 0) 3535b88ce6f2SRichard Henderson TRANS(EDGE32LN, VIS2, gen_edge, a, 32, 0, 1) 3536b88ce6f2SRichard Henderson 353745bfed3bSRichard Henderson static bool do_rrr(DisasContext *dc, arg_r_r_r *a, 353845bfed3bSRichard Henderson void (*func)(TCGv, TCGv, TCGv)) 353945bfed3bSRichard Henderson { 354045bfed3bSRichard Henderson TCGv dst = gen_dest_gpr(dc, a->rd); 354145bfed3bSRichard Henderson TCGv src1 = gen_load_gpr(dc, a->rs1); 354245bfed3bSRichard Henderson TCGv src2 = gen_load_gpr(dc, a->rs2); 354345bfed3bSRichard Henderson 354445bfed3bSRichard Henderson func(dst, src1, src2); 354545bfed3bSRichard Henderson gen_store_gpr(dc, a->rd, dst); 354645bfed3bSRichard Henderson return advance_pc(dc); 354745bfed3bSRichard Henderson } 354845bfed3bSRichard Henderson 354945bfed3bSRichard Henderson TRANS(ARRAY8, VIS1, do_rrr, a, gen_helper_array8) 355045bfed3bSRichard Henderson TRANS(ARRAY16, VIS1, do_rrr, a, gen_op_array16) 355145bfed3bSRichard Henderson TRANS(ARRAY32, VIS1, do_rrr, a, gen_op_array32) 355245bfed3bSRichard Henderson 35539e20ca94SRichard Henderson static void gen_op_alignaddr(TCGv dst, TCGv s1, TCGv s2) 35549e20ca94SRichard Henderson { 35559e20ca94SRichard Henderson #ifdef TARGET_SPARC64 35569e20ca94SRichard Henderson TCGv tmp = tcg_temp_new(); 35579e20ca94SRichard Henderson 35589e20ca94SRichard Henderson tcg_gen_add_tl(tmp, s1, s2); 35599e20ca94SRichard Henderson tcg_gen_andi_tl(dst, tmp, -8); 35609e20ca94SRichard Henderson tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3); 35619e20ca94SRichard Henderson #else 35629e20ca94SRichard Henderson g_assert_not_reached(); 35639e20ca94SRichard Henderson #endif 35649e20ca94SRichard Henderson } 35659e20ca94SRichard Henderson 35669e20ca94SRichard Henderson static void gen_op_alignaddrl(TCGv dst, TCGv s1, TCGv s2) 35679e20ca94SRichard Henderson { 35689e20ca94SRichard Henderson #ifdef TARGET_SPARC64 35699e20ca94SRichard Henderson TCGv tmp = tcg_temp_new(); 35709e20ca94SRichard Henderson 35719e20ca94SRichard Henderson tcg_gen_add_tl(tmp, s1, s2); 35729e20ca94SRichard Henderson tcg_gen_andi_tl(dst, tmp, -8); 35739e20ca94SRichard Henderson tcg_gen_neg_tl(tmp, tmp); 35749e20ca94SRichard Henderson tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, tmp, 0, 3); 35759e20ca94SRichard Henderson #else 35769e20ca94SRichard Henderson g_assert_not_reached(); 35779e20ca94SRichard Henderson #endif 35789e20ca94SRichard Henderson } 35799e20ca94SRichard Henderson 35809e20ca94SRichard Henderson TRANS(ALIGNADDR, VIS1, do_rrr, a, gen_op_alignaddr) 35819e20ca94SRichard Henderson TRANS(ALIGNADDRL, VIS1, do_rrr, a, gen_op_alignaddrl) 35829e20ca94SRichard Henderson 358339ca3490SRichard Henderson static void gen_op_bmask(TCGv dst, TCGv s1, TCGv s2) 358439ca3490SRichard Henderson { 358539ca3490SRichard Henderson #ifdef TARGET_SPARC64 358639ca3490SRichard Henderson tcg_gen_add_tl(dst, s1, s2); 358739ca3490SRichard Henderson tcg_gen_deposit_tl(cpu_gsr, cpu_gsr, dst, 32, 32); 358839ca3490SRichard Henderson #else 358939ca3490SRichard Henderson g_assert_not_reached(); 359039ca3490SRichard Henderson #endif 359139ca3490SRichard Henderson } 359239ca3490SRichard Henderson 359339ca3490SRichard Henderson TRANS(BMASK, VIS2, do_rrr, a, gen_op_bmask) 359439ca3490SRichard Henderson 35955fc546eeSRichard Henderson static bool do_shift_r(DisasContext *dc, arg_shiftr *a, bool l, bool u) 35965fc546eeSRichard Henderson { 35975fc546eeSRichard Henderson TCGv dst, src1, src2; 35985fc546eeSRichard Henderson 35995fc546eeSRichard Henderson /* Reject 64-bit shifts for sparc32. */ 36005fc546eeSRichard Henderson if (avail_32(dc) && a->x) { 36015fc546eeSRichard Henderson return false; 36025fc546eeSRichard Henderson } 36035fc546eeSRichard Henderson 36045fc546eeSRichard Henderson src2 = tcg_temp_new(); 36055fc546eeSRichard Henderson tcg_gen_andi_tl(src2, gen_load_gpr(dc, a->rs2), a->x ? 63 : 31); 36065fc546eeSRichard Henderson src1 = gen_load_gpr(dc, a->rs1); 36075fc546eeSRichard Henderson dst = gen_dest_gpr(dc, a->rd); 36085fc546eeSRichard Henderson 36095fc546eeSRichard Henderson if (l) { 36105fc546eeSRichard Henderson tcg_gen_shl_tl(dst, src1, src2); 36115fc546eeSRichard Henderson if (!a->x) { 36125fc546eeSRichard Henderson tcg_gen_ext32u_tl(dst, dst); 36135fc546eeSRichard Henderson } 36145fc546eeSRichard Henderson } else if (u) { 36155fc546eeSRichard Henderson if (!a->x) { 36165fc546eeSRichard Henderson tcg_gen_ext32u_tl(dst, src1); 36175fc546eeSRichard Henderson src1 = dst; 36185fc546eeSRichard Henderson } 36195fc546eeSRichard Henderson tcg_gen_shr_tl(dst, src1, src2); 36205fc546eeSRichard Henderson } else { 36215fc546eeSRichard Henderson if (!a->x) { 36225fc546eeSRichard Henderson tcg_gen_ext32s_tl(dst, src1); 36235fc546eeSRichard Henderson src1 = dst; 36245fc546eeSRichard Henderson } 36255fc546eeSRichard Henderson tcg_gen_sar_tl(dst, src1, src2); 36265fc546eeSRichard Henderson } 36275fc546eeSRichard Henderson gen_store_gpr(dc, a->rd, dst); 36285fc546eeSRichard Henderson return advance_pc(dc); 36295fc546eeSRichard Henderson } 36305fc546eeSRichard Henderson 36315fc546eeSRichard Henderson TRANS(SLL_r, ALL, do_shift_r, a, true, true) 36325fc546eeSRichard Henderson TRANS(SRL_r, ALL, do_shift_r, a, false, true) 36335fc546eeSRichard Henderson TRANS(SRA_r, ALL, do_shift_r, a, false, false) 36345fc546eeSRichard Henderson 36355fc546eeSRichard Henderson static bool do_shift_i(DisasContext *dc, arg_shifti *a, bool l, bool u) 36365fc546eeSRichard Henderson { 36375fc546eeSRichard Henderson TCGv dst, src1; 36385fc546eeSRichard Henderson 36395fc546eeSRichard Henderson /* Reject 64-bit shifts for sparc32. */ 36405fc546eeSRichard Henderson if (avail_32(dc) && (a->x || a->i >= 32)) { 36415fc546eeSRichard Henderson return false; 36425fc546eeSRichard Henderson } 36435fc546eeSRichard Henderson 36445fc546eeSRichard Henderson src1 = gen_load_gpr(dc, a->rs1); 36455fc546eeSRichard Henderson dst = gen_dest_gpr(dc, a->rd); 36465fc546eeSRichard Henderson 36475fc546eeSRichard Henderson if (avail_32(dc) || a->x) { 36485fc546eeSRichard Henderson if (l) { 36495fc546eeSRichard Henderson tcg_gen_shli_tl(dst, src1, a->i); 36505fc546eeSRichard Henderson } else if (u) { 36515fc546eeSRichard Henderson tcg_gen_shri_tl(dst, src1, a->i); 36525fc546eeSRichard Henderson } else { 36535fc546eeSRichard Henderson tcg_gen_sari_tl(dst, src1, a->i); 36545fc546eeSRichard Henderson } 36555fc546eeSRichard Henderson } else { 36565fc546eeSRichard Henderson if (l) { 36575fc546eeSRichard Henderson tcg_gen_deposit_z_tl(dst, src1, a->i, 32 - a->i); 36585fc546eeSRichard Henderson } else if (u) { 36595fc546eeSRichard Henderson tcg_gen_extract_tl(dst, src1, a->i, 32 - a->i); 36605fc546eeSRichard Henderson } else { 36615fc546eeSRichard Henderson tcg_gen_sextract_tl(dst, src1, a->i, 32 - a->i); 36625fc546eeSRichard Henderson } 36635fc546eeSRichard Henderson } 36645fc546eeSRichard Henderson gen_store_gpr(dc, a->rd, dst); 36655fc546eeSRichard Henderson return advance_pc(dc); 36665fc546eeSRichard Henderson } 36675fc546eeSRichard Henderson 36685fc546eeSRichard Henderson TRANS(SLL_i, ALL, do_shift_i, a, true, true) 36695fc546eeSRichard Henderson TRANS(SRL_i, ALL, do_shift_i, a, false, true) 36705fc546eeSRichard Henderson TRANS(SRA_i, ALL, do_shift_i, a, false, false) 36715fc546eeSRichard Henderson 3672fb4ed7aaSRichard Henderson static TCGv gen_rs2_or_imm(DisasContext *dc, bool imm, int rs2_or_imm) 3673fb4ed7aaSRichard Henderson { 3674fb4ed7aaSRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 3675fb4ed7aaSRichard Henderson if (!imm && rs2_or_imm & ~0x1f) { 3676fb4ed7aaSRichard Henderson return NULL; 3677fb4ed7aaSRichard Henderson } 3678fb4ed7aaSRichard Henderson if (imm || rs2_or_imm == 0) { 3679fb4ed7aaSRichard Henderson return tcg_constant_tl(rs2_or_imm); 3680fb4ed7aaSRichard Henderson } else { 3681fb4ed7aaSRichard Henderson return cpu_regs[rs2_or_imm]; 3682fb4ed7aaSRichard Henderson } 3683fb4ed7aaSRichard Henderson } 3684fb4ed7aaSRichard Henderson 3685fb4ed7aaSRichard Henderson static bool do_mov_cond(DisasContext *dc, DisasCompare *cmp, int rd, TCGv src2) 3686fb4ed7aaSRichard Henderson { 3687fb4ed7aaSRichard Henderson TCGv dst = gen_load_gpr(dc, rd); 3688c8507ebfSRichard Henderson TCGv c2 = tcg_constant_tl(cmp->c2); 3689fb4ed7aaSRichard Henderson 3690c8507ebfSRichard Henderson tcg_gen_movcond_tl(cmp->cond, dst, cmp->c1, c2, src2, dst); 3691fb4ed7aaSRichard Henderson gen_store_gpr(dc, rd, dst); 3692fb4ed7aaSRichard Henderson return advance_pc(dc); 3693fb4ed7aaSRichard Henderson } 3694fb4ed7aaSRichard Henderson 3695fb4ed7aaSRichard Henderson static bool trans_MOVcc(DisasContext *dc, arg_MOVcc *a) 3696fb4ed7aaSRichard Henderson { 3697fb4ed7aaSRichard Henderson TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm); 3698fb4ed7aaSRichard Henderson DisasCompare cmp; 3699fb4ed7aaSRichard Henderson 3700fb4ed7aaSRichard Henderson if (src2 == NULL) { 3701fb4ed7aaSRichard Henderson return false; 3702fb4ed7aaSRichard Henderson } 3703fb4ed7aaSRichard Henderson gen_compare(&cmp, a->cc, a->cond, dc); 3704fb4ed7aaSRichard Henderson return do_mov_cond(dc, &cmp, a->rd, src2); 3705fb4ed7aaSRichard Henderson } 3706fb4ed7aaSRichard Henderson 3707fb4ed7aaSRichard Henderson static bool trans_MOVfcc(DisasContext *dc, arg_MOVfcc *a) 3708fb4ed7aaSRichard Henderson { 3709fb4ed7aaSRichard Henderson TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm); 3710fb4ed7aaSRichard Henderson DisasCompare cmp; 3711fb4ed7aaSRichard Henderson 3712fb4ed7aaSRichard Henderson if (src2 == NULL) { 3713fb4ed7aaSRichard Henderson return false; 3714fb4ed7aaSRichard Henderson } 3715fb4ed7aaSRichard Henderson gen_fcompare(&cmp, a->cc, a->cond); 3716fb4ed7aaSRichard Henderson return do_mov_cond(dc, &cmp, a->rd, src2); 3717fb4ed7aaSRichard Henderson } 3718fb4ed7aaSRichard Henderson 3719fb4ed7aaSRichard Henderson static bool trans_MOVR(DisasContext *dc, arg_MOVR *a) 3720fb4ed7aaSRichard Henderson { 3721fb4ed7aaSRichard Henderson TCGv src2 = gen_rs2_or_imm(dc, a->imm, a->rs2_or_imm); 3722fb4ed7aaSRichard Henderson DisasCompare cmp; 3723fb4ed7aaSRichard Henderson 3724fb4ed7aaSRichard Henderson if (src2 == NULL) { 3725fb4ed7aaSRichard Henderson return false; 3726fb4ed7aaSRichard Henderson } 37272c4f56c9SRichard Henderson if (!gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1))) { 37282c4f56c9SRichard Henderson return false; 37292c4f56c9SRichard Henderson } 3730fb4ed7aaSRichard Henderson return do_mov_cond(dc, &cmp, a->rd, src2); 3731fb4ed7aaSRichard Henderson } 3732fb4ed7aaSRichard Henderson 373386b82fe0SRichard Henderson static bool do_add_special(DisasContext *dc, arg_r_r_ri *a, 373486b82fe0SRichard Henderson bool (*func)(DisasContext *dc, int rd, TCGv src)) 373586b82fe0SRichard Henderson { 373686b82fe0SRichard Henderson TCGv src1, sum; 373786b82fe0SRichard Henderson 373886b82fe0SRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 373986b82fe0SRichard Henderson if (!a->imm && a->rs2_or_imm & ~0x1f) { 374086b82fe0SRichard Henderson return false; 374186b82fe0SRichard Henderson } 374286b82fe0SRichard Henderson 374386b82fe0SRichard Henderson /* 374486b82fe0SRichard Henderson * Always load the sum into a new temporary. 374586b82fe0SRichard Henderson * This is required to capture the value across a window change, 374686b82fe0SRichard Henderson * e.g. SAVE and RESTORE, and may be optimized away otherwise. 374786b82fe0SRichard Henderson */ 374886b82fe0SRichard Henderson sum = tcg_temp_new(); 374986b82fe0SRichard Henderson src1 = gen_load_gpr(dc, a->rs1); 375086b82fe0SRichard Henderson if (a->imm || a->rs2_or_imm == 0) { 375186b82fe0SRichard Henderson tcg_gen_addi_tl(sum, src1, a->rs2_or_imm); 375286b82fe0SRichard Henderson } else { 375386b82fe0SRichard Henderson tcg_gen_add_tl(sum, src1, cpu_regs[a->rs2_or_imm]); 375486b82fe0SRichard Henderson } 375586b82fe0SRichard Henderson return func(dc, a->rd, sum); 375686b82fe0SRichard Henderson } 375786b82fe0SRichard Henderson 375886b82fe0SRichard Henderson static bool do_jmpl(DisasContext *dc, int rd, TCGv src) 375986b82fe0SRichard Henderson { 376086b82fe0SRichard Henderson /* 376186b82fe0SRichard Henderson * Preserve pc across advance, so that we can delay 376286b82fe0SRichard Henderson * the writeback to rd until after src is consumed. 376386b82fe0SRichard Henderson */ 376486b82fe0SRichard Henderson target_ulong cur_pc = dc->pc; 376586b82fe0SRichard Henderson 376686b82fe0SRichard Henderson gen_check_align(dc, src, 3); 376786b82fe0SRichard Henderson 376886b82fe0SRichard Henderson gen_mov_pc_npc(dc); 376986b82fe0SRichard Henderson tcg_gen_mov_tl(cpu_npc, src); 377086b82fe0SRichard Henderson gen_address_mask(dc, cpu_npc); 377186b82fe0SRichard Henderson gen_store_gpr(dc, rd, tcg_constant_tl(cur_pc)); 377286b82fe0SRichard Henderson 377386b82fe0SRichard Henderson dc->npc = DYNAMIC_PC_LOOKUP; 377486b82fe0SRichard Henderson return true; 377586b82fe0SRichard Henderson } 377686b82fe0SRichard Henderson 377786b82fe0SRichard Henderson TRANS(JMPL, ALL, do_add_special, a, do_jmpl) 377886b82fe0SRichard Henderson 377986b82fe0SRichard Henderson static bool do_rett(DisasContext *dc, int rd, TCGv src) 378086b82fe0SRichard Henderson { 378186b82fe0SRichard Henderson if (!supervisor(dc)) { 378286b82fe0SRichard Henderson return raise_priv(dc); 378386b82fe0SRichard Henderson } 378486b82fe0SRichard Henderson 378586b82fe0SRichard Henderson gen_check_align(dc, src, 3); 378686b82fe0SRichard Henderson 378786b82fe0SRichard Henderson gen_mov_pc_npc(dc); 378886b82fe0SRichard Henderson tcg_gen_mov_tl(cpu_npc, src); 378986b82fe0SRichard Henderson gen_helper_rett(tcg_env); 379086b82fe0SRichard Henderson 379186b82fe0SRichard Henderson dc->npc = DYNAMIC_PC; 379286b82fe0SRichard Henderson return true; 379386b82fe0SRichard Henderson } 379486b82fe0SRichard Henderson 379586b82fe0SRichard Henderson TRANS(RETT, 32, do_add_special, a, do_rett) 379686b82fe0SRichard Henderson 379786b82fe0SRichard Henderson static bool do_return(DisasContext *dc, int rd, TCGv src) 379886b82fe0SRichard Henderson { 379986b82fe0SRichard Henderson gen_check_align(dc, src, 3); 38000dfae4f9SRichard Henderson gen_helper_restore(tcg_env); 380186b82fe0SRichard Henderson 380286b82fe0SRichard Henderson gen_mov_pc_npc(dc); 380386b82fe0SRichard Henderson tcg_gen_mov_tl(cpu_npc, src); 380486b82fe0SRichard Henderson gen_address_mask(dc, cpu_npc); 380586b82fe0SRichard Henderson 380686b82fe0SRichard Henderson dc->npc = DYNAMIC_PC_LOOKUP; 380786b82fe0SRichard Henderson return true; 380886b82fe0SRichard Henderson } 380986b82fe0SRichard Henderson 381086b82fe0SRichard Henderson TRANS(RETURN, 64, do_add_special, a, do_return) 381186b82fe0SRichard Henderson 3812d3825800SRichard Henderson static bool do_save(DisasContext *dc, int rd, TCGv src) 3813d3825800SRichard Henderson { 3814d3825800SRichard Henderson gen_helper_save(tcg_env); 3815d3825800SRichard Henderson gen_store_gpr(dc, rd, src); 3816d3825800SRichard Henderson return advance_pc(dc); 3817d3825800SRichard Henderson } 3818d3825800SRichard Henderson 3819d3825800SRichard Henderson TRANS(SAVE, ALL, do_add_special, a, do_save) 3820d3825800SRichard Henderson 3821d3825800SRichard Henderson static bool do_restore(DisasContext *dc, int rd, TCGv src) 3822d3825800SRichard Henderson { 3823d3825800SRichard Henderson gen_helper_restore(tcg_env); 3824d3825800SRichard Henderson gen_store_gpr(dc, rd, src); 3825d3825800SRichard Henderson return advance_pc(dc); 3826d3825800SRichard Henderson } 3827d3825800SRichard Henderson 3828d3825800SRichard Henderson TRANS(RESTORE, ALL, do_add_special, a, do_restore) 3829d3825800SRichard Henderson 38308f75b8a4SRichard Henderson static bool do_done_retry(DisasContext *dc, bool done) 38318f75b8a4SRichard Henderson { 38328f75b8a4SRichard Henderson if (!supervisor(dc)) { 38338f75b8a4SRichard Henderson return raise_priv(dc); 38348f75b8a4SRichard Henderson } 38358f75b8a4SRichard Henderson dc->npc = DYNAMIC_PC; 38368f75b8a4SRichard Henderson dc->pc = DYNAMIC_PC; 38378f75b8a4SRichard Henderson translator_io_start(&dc->base); 38388f75b8a4SRichard Henderson if (done) { 38398f75b8a4SRichard Henderson gen_helper_done(tcg_env); 38408f75b8a4SRichard Henderson } else { 38418f75b8a4SRichard Henderson gen_helper_retry(tcg_env); 38428f75b8a4SRichard Henderson } 38438f75b8a4SRichard Henderson return true; 38448f75b8a4SRichard Henderson } 38458f75b8a4SRichard Henderson 38468f75b8a4SRichard Henderson TRANS(DONE, 64, do_done_retry, true) 38478f75b8a4SRichard Henderson TRANS(RETRY, 64, do_done_retry, false) 38488f75b8a4SRichard Henderson 38490880d20bSRichard Henderson /* 38500880d20bSRichard Henderson * Major opcode 11 -- load and store instructions 38510880d20bSRichard Henderson */ 38520880d20bSRichard Henderson 38530880d20bSRichard Henderson static TCGv gen_ldst_addr(DisasContext *dc, int rs1, bool imm, int rs2_or_imm) 38540880d20bSRichard Henderson { 38550880d20bSRichard Henderson TCGv addr, tmp = NULL; 38560880d20bSRichard Henderson 38570880d20bSRichard Henderson /* For simplicity, we under-decoded the rs2 form. */ 38580880d20bSRichard Henderson if (!imm && rs2_or_imm & ~0x1f) { 38590880d20bSRichard Henderson return NULL; 38600880d20bSRichard Henderson } 38610880d20bSRichard Henderson 38620880d20bSRichard Henderson addr = gen_load_gpr(dc, rs1); 38630880d20bSRichard Henderson if (rs2_or_imm) { 38640880d20bSRichard Henderson tmp = tcg_temp_new(); 38650880d20bSRichard Henderson if (imm) { 38660880d20bSRichard Henderson tcg_gen_addi_tl(tmp, addr, rs2_or_imm); 38670880d20bSRichard Henderson } else { 38680880d20bSRichard Henderson tcg_gen_add_tl(tmp, addr, cpu_regs[rs2_or_imm]); 38690880d20bSRichard Henderson } 38700880d20bSRichard Henderson addr = tmp; 38710880d20bSRichard Henderson } 38720880d20bSRichard Henderson if (AM_CHECK(dc)) { 38730880d20bSRichard Henderson if (!tmp) { 38740880d20bSRichard Henderson tmp = tcg_temp_new(); 38750880d20bSRichard Henderson } 38760880d20bSRichard Henderson tcg_gen_ext32u_tl(tmp, addr); 38770880d20bSRichard Henderson addr = tmp; 38780880d20bSRichard Henderson } 38790880d20bSRichard Henderson return addr; 38800880d20bSRichard Henderson } 38810880d20bSRichard Henderson 38820880d20bSRichard Henderson static bool do_ld_gpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop) 38830880d20bSRichard Henderson { 38840880d20bSRichard Henderson TCGv reg, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 38850880d20bSRichard Henderson DisasASI da; 38860880d20bSRichard Henderson 38870880d20bSRichard Henderson if (addr == NULL) { 38880880d20bSRichard Henderson return false; 38890880d20bSRichard Henderson } 38900880d20bSRichard Henderson da = resolve_asi(dc, a->asi, mop); 38910880d20bSRichard Henderson 38920880d20bSRichard Henderson reg = gen_dest_gpr(dc, a->rd); 389342071fc1SRichard Henderson gen_ld_asi(dc, &da, reg, addr); 38940880d20bSRichard Henderson gen_store_gpr(dc, a->rd, reg); 38950880d20bSRichard Henderson return advance_pc(dc); 38960880d20bSRichard Henderson } 38970880d20bSRichard Henderson 38980880d20bSRichard Henderson TRANS(LDUW, ALL, do_ld_gpr, a, MO_TEUL) 38990880d20bSRichard Henderson TRANS(LDUB, ALL, do_ld_gpr, a, MO_UB) 39000880d20bSRichard Henderson TRANS(LDUH, ALL, do_ld_gpr, a, MO_TEUW) 39010880d20bSRichard Henderson TRANS(LDSB, ALL, do_ld_gpr, a, MO_SB) 39020880d20bSRichard Henderson TRANS(LDSH, ALL, do_ld_gpr, a, MO_TESW) 39030880d20bSRichard Henderson TRANS(LDSW, 64, do_ld_gpr, a, MO_TESL) 39040880d20bSRichard Henderson TRANS(LDX, 64, do_ld_gpr, a, MO_TEUQ) 39050880d20bSRichard Henderson 39060880d20bSRichard Henderson static bool do_st_gpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop) 39070880d20bSRichard Henderson { 39080880d20bSRichard Henderson TCGv reg, addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 39090880d20bSRichard Henderson DisasASI da; 39100880d20bSRichard Henderson 39110880d20bSRichard Henderson if (addr == NULL) { 39120880d20bSRichard Henderson return false; 39130880d20bSRichard Henderson } 39140880d20bSRichard Henderson da = resolve_asi(dc, a->asi, mop); 39150880d20bSRichard Henderson 39160880d20bSRichard Henderson reg = gen_load_gpr(dc, a->rd); 391742071fc1SRichard Henderson gen_st_asi(dc, &da, reg, addr); 39180880d20bSRichard Henderson return advance_pc(dc); 39190880d20bSRichard Henderson } 39200880d20bSRichard Henderson 39210880d20bSRichard Henderson TRANS(STW, ALL, do_st_gpr, a, MO_TEUL) 39220880d20bSRichard Henderson TRANS(STB, ALL, do_st_gpr, a, MO_UB) 39230880d20bSRichard Henderson TRANS(STH, ALL, do_st_gpr, a, MO_TEUW) 39240880d20bSRichard Henderson TRANS(STX, 64, do_st_gpr, a, MO_TEUQ) 39250880d20bSRichard Henderson 39260880d20bSRichard Henderson static bool trans_LDD(DisasContext *dc, arg_r_r_ri_asi *a) 39270880d20bSRichard Henderson { 39280880d20bSRichard Henderson TCGv addr; 39290880d20bSRichard Henderson DisasASI da; 39300880d20bSRichard Henderson 39310880d20bSRichard Henderson if (a->rd & 1) { 39320880d20bSRichard Henderson return false; 39330880d20bSRichard Henderson } 39340880d20bSRichard Henderson addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 39350880d20bSRichard Henderson if (addr == NULL) { 39360880d20bSRichard Henderson return false; 39370880d20bSRichard Henderson } 39380880d20bSRichard Henderson da = resolve_asi(dc, a->asi, MO_TEUQ); 393942071fc1SRichard Henderson gen_ldda_asi(dc, &da, addr, a->rd); 39400880d20bSRichard Henderson return advance_pc(dc); 39410880d20bSRichard Henderson } 39420880d20bSRichard Henderson 39430880d20bSRichard Henderson static bool trans_STD(DisasContext *dc, arg_r_r_ri_asi *a) 39440880d20bSRichard Henderson { 39450880d20bSRichard Henderson TCGv addr; 39460880d20bSRichard Henderson DisasASI da; 39470880d20bSRichard Henderson 39480880d20bSRichard Henderson if (a->rd & 1) { 39490880d20bSRichard Henderson return false; 39500880d20bSRichard Henderson } 39510880d20bSRichard Henderson addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 39520880d20bSRichard Henderson if (addr == NULL) { 39530880d20bSRichard Henderson return false; 39540880d20bSRichard Henderson } 39550880d20bSRichard Henderson da = resolve_asi(dc, a->asi, MO_TEUQ); 395642071fc1SRichard Henderson gen_stda_asi(dc, &da, addr, a->rd); 39570880d20bSRichard Henderson return advance_pc(dc); 39580880d20bSRichard Henderson } 39590880d20bSRichard Henderson 3960cf07cd1eSRichard Henderson static bool trans_LDSTUB(DisasContext *dc, arg_r_r_ri_asi *a) 3961cf07cd1eSRichard Henderson { 3962cf07cd1eSRichard Henderson TCGv addr, reg; 3963cf07cd1eSRichard Henderson DisasASI da; 3964cf07cd1eSRichard Henderson 3965cf07cd1eSRichard Henderson addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 3966cf07cd1eSRichard Henderson if (addr == NULL) { 3967cf07cd1eSRichard Henderson return false; 3968cf07cd1eSRichard Henderson } 3969cf07cd1eSRichard Henderson da = resolve_asi(dc, a->asi, MO_UB); 3970cf07cd1eSRichard Henderson 3971cf07cd1eSRichard Henderson reg = gen_dest_gpr(dc, a->rd); 3972cf07cd1eSRichard Henderson gen_ldstub_asi(dc, &da, reg, addr); 3973cf07cd1eSRichard Henderson gen_store_gpr(dc, a->rd, reg); 3974cf07cd1eSRichard Henderson return advance_pc(dc); 3975cf07cd1eSRichard Henderson } 3976cf07cd1eSRichard Henderson 3977dca544b9SRichard Henderson static bool trans_SWAP(DisasContext *dc, arg_r_r_ri_asi *a) 3978dca544b9SRichard Henderson { 3979dca544b9SRichard Henderson TCGv addr, dst, src; 3980dca544b9SRichard Henderson DisasASI da; 3981dca544b9SRichard Henderson 3982dca544b9SRichard Henderson addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 3983dca544b9SRichard Henderson if (addr == NULL) { 3984dca544b9SRichard Henderson return false; 3985dca544b9SRichard Henderson } 3986dca544b9SRichard Henderson da = resolve_asi(dc, a->asi, MO_TEUL); 3987dca544b9SRichard Henderson 3988dca544b9SRichard Henderson dst = gen_dest_gpr(dc, a->rd); 3989dca544b9SRichard Henderson src = gen_load_gpr(dc, a->rd); 3990dca544b9SRichard Henderson gen_swap_asi(dc, &da, dst, src, addr); 3991dca544b9SRichard Henderson gen_store_gpr(dc, a->rd, dst); 3992dca544b9SRichard Henderson return advance_pc(dc); 3993dca544b9SRichard Henderson } 3994dca544b9SRichard Henderson 3995d0a11d25SRichard Henderson static bool do_casa(DisasContext *dc, arg_r_r_ri_asi *a, MemOp mop) 3996d0a11d25SRichard Henderson { 3997d0a11d25SRichard Henderson TCGv addr, o, n, c; 3998d0a11d25SRichard Henderson DisasASI da; 3999d0a11d25SRichard Henderson 4000d0a11d25SRichard Henderson addr = gen_ldst_addr(dc, a->rs1, true, 0); 4001d0a11d25SRichard Henderson if (addr == NULL) { 4002d0a11d25SRichard Henderson return false; 4003d0a11d25SRichard Henderson } 4004d0a11d25SRichard Henderson da = resolve_asi(dc, a->asi, mop); 4005d0a11d25SRichard Henderson 4006d0a11d25SRichard Henderson o = gen_dest_gpr(dc, a->rd); 4007d0a11d25SRichard Henderson n = gen_load_gpr(dc, a->rd); 4008d0a11d25SRichard Henderson c = gen_load_gpr(dc, a->rs2_or_imm); 4009d0a11d25SRichard Henderson gen_cas_asi(dc, &da, o, n, c, addr); 4010d0a11d25SRichard Henderson gen_store_gpr(dc, a->rd, o); 4011d0a11d25SRichard Henderson return advance_pc(dc); 4012d0a11d25SRichard Henderson } 4013d0a11d25SRichard Henderson 4014d0a11d25SRichard Henderson TRANS(CASA, CASA, do_casa, a, MO_TEUL) 4015d0a11d25SRichard Henderson TRANS(CASXA, 64, do_casa, a, MO_TEUQ) 4016d0a11d25SRichard Henderson 401706c060d9SRichard Henderson static bool do_ld_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz) 401806c060d9SRichard Henderson { 401906c060d9SRichard Henderson TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 402006c060d9SRichard Henderson DisasASI da; 402106c060d9SRichard Henderson 402206c060d9SRichard Henderson if (addr == NULL) { 402306c060d9SRichard Henderson return false; 402406c060d9SRichard Henderson } 402506c060d9SRichard Henderson if (gen_trap_ifnofpu(dc)) { 402606c060d9SRichard Henderson return true; 402706c060d9SRichard Henderson } 402806c060d9SRichard Henderson if (sz == MO_128 && gen_trap_float128(dc)) { 402906c060d9SRichard Henderson return true; 403006c060d9SRichard Henderson } 403106c060d9SRichard Henderson da = resolve_asi(dc, a->asi, MO_TE | sz); 4032287b1152SRichard Henderson gen_ldf_asi(dc, &da, sz, addr, a->rd); 403306c060d9SRichard Henderson gen_update_fprs_dirty(dc, a->rd); 403406c060d9SRichard Henderson return advance_pc(dc); 403506c060d9SRichard Henderson } 403606c060d9SRichard Henderson 403706c060d9SRichard Henderson TRANS(LDF, ALL, do_ld_fpr, a, MO_32) 403806c060d9SRichard Henderson TRANS(LDDF, ALL, do_ld_fpr, a, MO_64) 403906c060d9SRichard Henderson TRANS(LDQF, ALL, do_ld_fpr, a, MO_128) 404006c060d9SRichard Henderson 4041287b1152SRichard Henderson TRANS(LDFA, 64, do_ld_fpr, a, MO_32) 4042287b1152SRichard Henderson TRANS(LDDFA, 64, do_ld_fpr, a, MO_64) 4043287b1152SRichard Henderson TRANS(LDQFA, 64, do_ld_fpr, a, MO_128) 4044287b1152SRichard Henderson 404506c060d9SRichard Henderson static bool do_st_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz) 404606c060d9SRichard Henderson { 404706c060d9SRichard Henderson TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 404806c060d9SRichard Henderson DisasASI da; 404906c060d9SRichard Henderson 405006c060d9SRichard Henderson if (addr == NULL) { 405106c060d9SRichard Henderson return false; 405206c060d9SRichard Henderson } 405306c060d9SRichard Henderson if (gen_trap_ifnofpu(dc)) { 405406c060d9SRichard Henderson return true; 405506c060d9SRichard Henderson } 405606c060d9SRichard Henderson if (sz == MO_128 && gen_trap_float128(dc)) { 405706c060d9SRichard Henderson return true; 405806c060d9SRichard Henderson } 405906c060d9SRichard Henderson da = resolve_asi(dc, a->asi, MO_TE | sz); 4060287b1152SRichard Henderson gen_stf_asi(dc, &da, sz, addr, a->rd); 406106c060d9SRichard Henderson return advance_pc(dc); 406206c060d9SRichard Henderson } 406306c060d9SRichard Henderson 406406c060d9SRichard Henderson TRANS(STF, ALL, do_st_fpr, a, MO_32) 406506c060d9SRichard Henderson TRANS(STDF, ALL, do_st_fpr, a, MO_64) 406606c060d9SRichard Henderson TRANS(STQF, ALL, do_st_fpr, a, MO_128) 406706c060d9SRichard Henderson 4068287b1152SRichard Henderson TRANS(STFA, 64, do_st_fpr, a, MO_32) 4069287b1152SRichard Henderson TRANS(STDFA, 64, do_st_fpr, a, MO_64) 4070287b1152SRichard Henderson TRANS(STQFA, 64, do_st_fpr, a, MO_128) 4071287b1152SRichard Henderson 407206c060d9SRichard Henderson static bool trans_STDFQ(DisasContext *dc, arg_STDFQ *a) 407306c060d9SRichard Henderson { 407406c060d9SRichard Henderson if (!avail_32(dc)) { 407506c060d9SRichard Henderson return false; 407606c060d9SRichard Henderson } 407706c060d9SRichard Henderson if (!supervisor(dc)) { 407806c060d9SRichard Henderson return raise_priv(dc); 407906c060d9SRichard Henderson } 408006c060d9SRichard Henderson if (gen_trap_ifnofpu(dc)) { 408106c060d9SRichard Henderson return true; 408206c060d9SRichard Henderson } 408306c060d9SRichard Henderson gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR); 408406c060d9SRichard Henderson return true; 408506c060d9SRichard Henderson } 408606c060d9SRichard Henderson 4087d8c5b92fSRichard Henderson static bool trans_LDFSR(DisasContext *dc, arg_r_r_ri *a) 40883d3c0673SRichard Henderson { 40893590f01eSRichard Henderson TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 4090d8c5b92fSRichard Henderson TCGv_i32 tmp; 40913590f01eSRichard Henderson 40923d3c0673SRichard Henderson if (addr == NULL) { 40933d3c0673SRichard Henderson return false; 40943d3c0673SRichard Henderson } 40953d3c0673SRichard Henderson if (gen_trap_ifnofpu(dc)) { 40963d3c0673SRichard Henderson return true; 40973d3c0673SRichard Henderson } 4098d8c5b92fSRichard Henderson 4099d8c5b92fSRichard Henderson tmp = tcg_temp_new_i32(); 4100d8c5b92fSRichard Henderson tcg_gen_qemu_ld_i32(tmp, addr, dc->mem_idx, MO_TEUL | MO_ALIGN); 4101d8c5b92fSRichard Henderson 4102d8c5b92fSRichard Henderson tcg_gen_extract_i32(cpu_fcc[0], tmp, FSR_FCC0_SHIFT, 2); 4103d8c5b92fSRichard Henderson /* LDFSR does not change FCC[1-3]. */ 4104d8c5b92fSRichard Henderson 4105d8c5b92fSRichard Henderson gen_helper_set_fsr_nofcc_noftt(tcg_env, tmp); 41063d3c0673SRichard Henderson return advance_pc(dc); 41073d3c0673SRichard Henderson } 41083d3c0673SRichard Henderson 4109d8c5b92fSRichard Henderson static bool trans_LDXFSR(DisasContext *dc, arg_r_r_ri *a) 4110d8c5b92fSRichard Henderson { 4111d8c5b92fSRichard Henderson #ifdef TARGET_SPARC64 4112d8c5b92fSRichard Henderson TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 4113d8c5b92fSRichard Henderson TCGv_i64 t64; 4114d8c5b92fSRichard Henderson TCGv_i32 lo, hi; 4115d8c5b92fSRichard Henderson 4116d8c5b92fSRichard Henderson if (addr == NULL) { 4117d8c5b92fSRichard Henderson return false; 4118d8c5b92fSRichard Henderson } 4119d8c5b92fSRichard Henderson if (gen_trap_ifnofpu(dc)) { 4120d8c5b92fSRichard Henderson return true; 4121d8c5b92fSRichard Henderson } 4122d8c5b92fSRichard Henderson 4123d8c5b92fSRichard Henderson t64 = tcg_temp_new_i64(); 4124d8c5b92fSRichard Henderson tcg_gen_qemu_ld_i64(t64, addr, dc->mem_idx, MO_TEUQ | MO_ALIGN); 4125d8c5b92fSRichard Henderson 4126d8c5b92fSRichard Henderson lo = tcg_temp_new_i32(); 4127d8c5b92fSRichard Henderson hi = cpu_fcc[3]; 4128d8c5b92fSRichard Henderson tcg_gen_extr_i64_i32(lo, hi, t64); 4129d8c5b92fSRichard Henderson tcg_gen_extract_i32(cpu_fcc[0], lo, FSR_FCC0_SHIFT, 2); 4130d8c5b92fSRichard Henderson tcg_gen_extract_i32(cpu_fcc[1], hi, FSR_FCC1_SHIFT - 32, 2); 4131d8c5b92fSRichard Henderson tcg_gen_extract_i32(cpu_fcc[2], hi, FSR_FCC2_SHIFT - 32, 2); 4132d8c5b92fSRichard Henderson tcg_gen_extract_i32(cpu_fcc[3], hi, FSR_FCC3_SHIFT - 32, 2); 4133d8c5b92fSRichard Henderson 4134d8c5b92fSRichard Henderson gen_helper_set_fsr_nofcc_noftt(tcg_env, lo); 4135d8c5b92fSRichard Henderson return advance_pc(dc); 4136d8c5b92fSRichard Henderson #else 4137d8c5b92fSRichard Henderson return false; 4138d8c5b92fSRichard Henderson #endif 4139d8c5b92fSRichard Henderson } 41403d3c0673SRichard Henderson 41413d3c0673SRichard Henderson static bool do_stfsr(DisasContext *dc, arg_r_r_ri *a, MemOp mop) 41423d3c0673SRichard Henderson { 41433d3c0673SRichard Henderson TCGv addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm); 41441ccd6e13SRichard Henderson TCGv fsr; 41451ccd6e13SRichard Henderson 41463d3c0673SRichard Henderson if (addr == NULL) { 41473d3c0673SRichard Henderson return false; 41483d3c0673SRichard Henderson } 41493d3c0673SRichard Henderson if (gen_trap_ifnofpu(dc)) { 41503d3c0673SRichard Henderson return true; 41513d3c0673SRichard Henderson } 41521ccd6e13SRichard Henderson 41531ccd6e13SRichard Henderson fsr = tcg_temp_new(); 41541ccd6e13SRichard Henderson gen_helper_get_fsr(fsr, tcg_env); 41551ccd6e13SRichard Henderson tcg_gen_qemu_st_tl(fsr, addr, dc->mem_idx, mop | MO_ALIGN); 41563d3c0673SRichard Henderson return advance_pc(dc); 41573d3c0673SRichard Henderson } 41583d3c0673SRichard Henderson 41593d3c0673SRichard Henderson TRANS(STFSR, ALL, do_stfsr, a, MO_TEUL) 41603d3c0673SRichard Henderson TRANS(STXFSR, 64, do_stfsr, a, MO_TEUQ) 41613d3c0673SRichard Henderson 41623a38260eSRichard Henderson static bool do_fc(DisasContext *dc, int rd, bool c) 41633a38260eSRichard Henderson { 41643a38260eSRichard Henderson uint64_t mask; 41653a38260eSRichard Henderson 41663a38260eSRichard Henderson if (gen_trap_ifnofpu(dc)) { 41673a38260eSRichard Henderson return true; 41683a38260eSRichard Henderson } 41693a38260eSRichard Henderson 41703a38260eSRichard Henderson if (rd & 1) { 41713a38260eSRichard Henderson mask = MAKE_64BIT_MASK(0, 32); 41723a38260eSRichard Henderson } else { 41733a38260eSRichard Henderson mask = MAKE_64BIT_MASK(32, 32); 41743a38260eSRichard Henderson } 41753a38260eSRichard Henderson if (c) { 41763a38260eSRichard Henderson tcg_gen_ori_i64(cpu_fpr[rd / 2], cpu_fpr[rd / 2], mask); 41773a38260eSRichard Henderson } else { 41783a38260eSRichard Henderson tcg_gen_andi_i64(cpu_fpr[rd / 2], cpu_fpr[rd / 2], ~mask); 41793a38260eSRichard Henderson } 41803a38260eSRichard Henderson gen_update_fprs_dirty(dc, rd); 41813a38260eSRichard Henderson return advance_pc(dc); 41823a38260eSRichard Henderson } 41833a38260eSRichard Henderson 41843a38260eSRichard Henderson TRANS(FZEROs, VIS1, do_fc, a->rd, 0) 41853a38260eSRichard Henderson TRANS(FONEs, VIS1, do_fc, a->rd, 1) 41863a38260eSRichard Henderson 41873a38260eSRichard Henderson static bool do_dc(DisasContext *dc, int rd, int64_t c) 41883a38260eSRichard Henderson { 41893a38260eSRichard Henderson if (gen_trap_ifnofpu(dc)) { 41903a38260eSRichard Henderson return true; 41913a38260eSRichard Henderson } 41923a38260eSRichard Henderson 41933a38260eSRichard Henderson tcg_gen_movi_i64(cpu_fpr[rd / 2], c); 41943a38260eSRichard Henderson gen_update_fprs_dirty(dc, rd); 41953a38260eSRichard Henderson return advance_pc(dc); 41963a38260eSRichard Henderson } 41973a38260eSRichard Henderson 41983a38260eSRichard Henderson TRANS(FZEROd, VIS1, do_dc, a->rd, 0) 41993a38260eSRichard Henderson TRANS(FONEd, VIS1, do_dc, a->rd, -1) 42003a38260eSRichard Henderson 4201baf3dbf2SRichard Henderson static bool do_ff(DisasContext *dc, arg_r_r *a, 4202baf3dbf2SRichard Henderson void (*func)(TCGv_i32, TCGv_i32)) 4203baf3dbf2SRichard Henderson { 4204baf3dbf2SRichard Henderson TCGv_i32 tmp; 4205baf3dbf2SRichard Henderson 4206baf3dbf2SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4207baf3dbf2SRichard Henderson return true; 4208baf3dbf2SRichard Henderson } 4209baf3dbf2SRichard Henderson 4210baf3dbf2SRichard Henderson tmp = gen_load_fpr_F(dc, a->rs); 4211baf3dbf2SRichard Henderson func(tmp, tmp); 4212baf3dbf2SRichard Henderson gen_store_fpr_F(dc, a->rd, tmp); 4213baf3dbf2SRichard Henderson return advance_pc(dc); 4214baf3dbf2SRichard Henderson } 4215baf3dbf2SRichard Henderson 4216baf3dbf2SRichard Henderson TRANS(FMOVs, ALL, do_ff, a, gen_op_fmovs) 4217baf3dbf2SRichard Henderson TRANS(FNEGs, ALL, do_ff, a, gen_op_fnegs) 4218baf3dbf2SRichard Henderson TRANS(FABSs, ALL, do_ff, a, gen_op_fabss) 4219baf3dbf2SRichard Henderson TRANS(FSRCs, VIS1, do_ff, a, tcg_gen_mov_i32) 4220baf3dbf2SRichard Henderson TRANS(FNOTs, VIS1, do_ff, a, tcg_gen_not_i32) 4221baf3dbf2SRichard Henderson 42222f722641SRichard Henderson static bool do_fd(DisasContext *dc, arg_r_r *a, 42232f722641SRichard Henderson void (*func)(TCGv_i32, TCGv_i64)) 42242f722641SRichard Henderson { 42252f722641SRichard Henderson TCGv_i32 dst; 42262f722641SRichard Henderson TCGv_i64 src; 42272f722641SRichard Henderson 42282f722641SRichard Henderson if (gen_trap_ifnofpu(dc)) { 42292f722641SRichard Henderson return true; 42302f722641SRichard Henderson } 42312f722641SRichard Henderson 4232388a6465SRichard Henderson dst = tcg_temp_new_i32(); 42332f722641SRichard Henderson src = gen_load_fpr_D(dc, a->rs); 42342f722641SRichard Henderson func(dst, src); 42352f722641SRichard Henderson gen_store_fpr_F(dc, a->rd, dst); 42362f722641SRichard Henderson return advance_pc(dc); 42372f722641SRichard Henderson } 42382f722641SRichard Henderson 42392f722641SRichard Henderson TRANS(FPACK16, VIS1, do_fd, a, gen_op_fpack16) 42402f722641SRichard Henderson TRANS(FPACKFIX, VIS1, do_fd, a, gen_op_fpackfix) 42412f722641SRichard Henderson 4242119cb94fSRichard Henderson static bool do_env_ff(DisasContext *dc, arg_r_r *a, 4243119cb94fSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) 4244119cb94fSRichard Henderson { 4245119cb94fSRichard Henderson TCGv_i32 tmp; 4246119cb94fSRichard Henderson 4247119cb94fSRichard Henderson if (gen_trap_ifnofpu(dc)) { 4248119cb94fSRichard Henderson return true; 4249119cb94fSRichard Henderson } 4250119cb94fSRichard Henderson 4251119cb94fSRichard Henderson tmp = gen_load_fpr_F(dc, a->rs); 4252119cb94fSRichard Henderson func(tmp, tcg_env, tmp); 4253119cb94fSRichard Henderson gen_store_fpr_F(dc, a->rd, tmp); 4254119cb94fSRichard Henderson return advance_pc(dc); 4255119cb94fSRichard Henderson } 4256119cb94fSRichard Henderson 4257119cb94fSRichard Henderson TRANS(FSQRTs, ALL, do_env_ff, a, gen_helper_fsqrts) 4258119cb94fSRichard Henderson TRANS(FiTOs, ALL, do_env_ff, a, gen_helper_fitos) 4259119cb94fSRichard Henderson TRANS(FsTOi, ALL, do_env_ff, a, gen_helper_fstoi) 4260119cb94fSRichard Henderson 42618c94bcd8SRichard Henderson static bool do_env_fd(DisasContext *dc, arg_r_r *a, 42628c94bcd8SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) 42638c94bcd8SRichard Henderson { 42648c94bcd8SRichard Henderson TCGv_i32 dst; 42658c94bcd8SRichard Henderson TCGv_i64 src; 42668c94bcd8SRichard Henderson 42678c94bcd8SRichard Henderson if (gen_trap_ifnofpu(dc)) { 42688c94bcd8SRichard Henderson return true; 42698c94bcd8SRichard Henderson } 42708c94bcd8SRichard Henderson 4271388a6465SRichard Henderson dst = tcg_temp_new_i32(); 42728c94bcd8SRichard Henderson src = gen_load_fpr_D(dc, a->rs); 42738c94bcd8SRichard Henderson func(dst, tcg_env, src); 42748c94bcd8SRichard Henderson gen_store_fpr_F(dc, a->rd, dst); 42758c94bcd8SRichard Henderson return advance_pc(dc); 42768c94bcd8SRichard Henderson } 42778c94bcd8SRichard Henderson 42788c94bcd8SRichard Henderson TRANS(FdTOs, ALL, do_env_fd, a, gen_helper_fdtos) 42798c94bcd8SRichard Henderson TRANS(FdTOi, ALL, do_env_fd, a, gen_helper_fdtoi) 42808c94bcd8SRichard Henderson TRANS(FxTOs, 64, do_env_fd, a, gen_helper_fxtos) 42818c94bcd8SRichard Henderson 4282c6d83e4fSRichard Henderson static bool do_dd(DisasContext *dc, arg_r_r *a, 4283c6d83e4fSRichard Henderson void (*func)(TCGv_i64, TCGv_i64)) 4284c6d83e4fSRichard Henderson { 4285c6d83e4fSRichard Henderson TCGv_i64 dst, src; 4286c6d83e4fSRichard Henderson 4287c6d83e4fSRichard Henderson if (gen_trap_ifnofpu(dc)) { 4288c6d83e4fSRichard Henderson return true; 4289c6d83e4fSRichard Henderson } 4290c6d83e4fSRichard Henderson 4291c6d83e4fSRichard Henderson dst = gen_dest_fpr_D(dc, a->rd); 4292c6d83e4fSRichard Henderson src = gen_load_fpr_D(dc, a->rs); 4293c6d83e4fSRichard Henderson func(dst, src); 4294c6d83e4fSRichard Henderson gen_store_fpr_D(dc, a->rd, dst); 4295c6d83e4fSRichard Henderson return advance_pc(dc); 4296c6d83e4fSRichard Henderson } 4297c6d83e4fSRichard Henderson 4298c6d83e4fSRichard Henderson TRANS(FMOVd, 64, do_dd, a, gen_op_fmovd) 4299c6d83e4fSRichard Henderson TRANS(FNEGd, 64, do_dd, a, gen_op_fnegd) 4300c6d83e4fSRichard Henderson TRANS(FABSd, 64, do_dd, a, gen_op_fabsd) 4301c6d83e4fSRichard Henderson TRANS(FSRCd, VIS1, do_dd, a, tcg_gen_mov_i64) 4302c6d83e4fSRichard Henderson TRANS(FNOTd, VIS1, do_dd, a, tcg_gen_not_i64) 4303c6d83e4fSRichard Henderson 43048aa418b3SRichard Henderson static bool do_env_dd(DisasContext *dc, arg_r_r *a, 43058aa418b3SRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) 43068aa418b3SRichard Henderson { 43078aa418b3SRichard Henderson TCGv_i64 dst, src; 43088aa418b3SRichard Henderson 43098aa418b3SRichard Henderson if (gen_trap_ifnofpu(dc)) { 43108aa418b3SRichard Henderson return true; 43118aa418b3SRichard Henderson } 43128aa418b3SRichard Henderson 43138aa418b3SRichard Henderson dst = gen_dest_fpr_D(dc, a->rd); 43148aa418b3SRichard Henderson src = gen_load_fpr_D(dc, a->rs); 43158aa418b3SRichard Henderson func(dst, tcg_env, src); 43168aa418b3SRichard Henderson gen_store_fpr_D(dc, a->rd, dst); 43178aa418b3SRichard Henderson return advance_pc(dc); 43188aa418b3SRichard Henderson } 43198aa418b3SRichard Henderson 43208aa418b3SRichard Henderson TRANS(FSQRTd, ALL, do_env_dd, a, gen_helper_fsqrtd) 43218aa418b3SRichard Henderson TRANS(FxTOd, 64, do_env_dd, a, gen_helper_fxtod) 43228aa418b3SRichard Henderson TRANS(FdTOx, 64, do_env_dd, a, gen_helper_fdtox) 43238aa418b3SRichard Henderson 4324199d43efSRichard Henderson static bool do_env_df(DisasContext *dc, arg_r_r *a, 4325199d43efSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) 4326199d43efSRichard Henderson { 4327199d43efSRichard Henderson TCGv_i64 dst; 4328199d43efSRichard Henderson TCGv_i32 src; 4329199d43efSRichard Henderson 4330199d43efSRichard Henderson if (gen_trap_ifnofpu(dc)) { 4331199d43efSRichard Henderson return true; 4332199d43efSRichard Henderson } 4333199d43efSRichard Henderson 4334199d43efSRichard Henderson dst = gen_dest_fpr_D(dc, a->rd); 4335199d43efSRichard Henderson src = gen_load_fpr_F(dc, a->rs); 4336199d43efSRichard Henderson func(dst, tcg_env, src); 4337199d43efSRichard Henderson gen_store_fpr_D(dc, a->rd, dst); 4338199d43efSRichard Henderson return advance_pc(dc); 4339199d43efSRichard Henderson } 4340199d43efSRichard Henderson 4341199d43efSRichard Henderson TRANS(FiTOd, ALL, do_env_df, a, gen_helper_fitod) 4342199d43efSRichard Henderson TRANS(FsTOd, ALL, do_env_df, a, gen_helper_fstod) 4343199d43efSRichard Henderson TRANS(FsTOx, 64, do_env_df, a, gen_helper_fstox) 4344199d43efSRichard Henderson 4345daf457d4SRichard Henderson static bool do_qq(DisasContext *dc, arg_r_r *a, 4346daf457d4SRichard Henderson void (*func)(TCGv_i128, TCGv_i128)) 4347f4e18df5SRichard Henderson { 434833ec4245SRichard Henderson TCGv_i128 t; 4349f4e18df5SRichard Henderson 4350f4e18df5SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4351f4e18df5SRichard Henderson return true; 4352f4e18df5SRichard Henderson } 4353f4e18df5SRichard Henderson if (gen_trap_float128(dc)) { 4354f4e18df5SRichard Henderson return true; 4355f4e18df5SRichard Henderson } 4356f4e18df5SRichard Henderson 4357f4e18df5SRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 435833ec4245SRichard Henderson t = gen_load_fpr_Q(dc, a->rs); 4359daf457d4SRichard Henderson func(t, t); 436033ec4245SRichard Henderson gen_store_fpr_Q(dc, a->rd, t); 4361f4e18df5SRichard Henderson return advance_pc(dc); 4362f4e18df5SRichard Henderson } 4363f4e18df5SRichard Henderson 4364daf457d4SRichard Henderson TRANS(FMOVq, 64, do_qq, a, tcg_gen_mov_i128) 4365daf457d4SRichard Henderson TRANS(FNEGq, 64, do_qq, a, gen_op_fnegq) 4366daf457d4SRichard Henderson TRANS(FABSq, 64, do_qq, a, gen_op_fabsq) 4367f4e18df5SRichard Henderson 4368c995216bSRichard Henderson static bool do_env_qq(DisasContext *dc, arg_r_r *a, 4369e41716beSRichard Henderson void (*func)(TCGv_i128, TCGv_env, TCGv_i128)) 4370c995216bSRichard Henderson { 4371e41716beSRichard Henderson TCGv_i128 t; 4372e41716beSRichard Henderson 4373c995216bSRichard Henderson if (gen_trap_ifnofpu(dc)) { 4374c995216bSRichard Henderson return true; 4375c995216bSRichard Henderson } 4376c995216bSRichard Henderson if (gen_trap_float128(dc)) { 4377c995216bSRichard Henderson return true; 4378c995216bSRichard Henderson } 4379c995216bSRichard Henderson 4380e41716beSRichard Henderson t = gen_load_fpr_Q(dc, a->rs); 4381e41716beSRichard Henderson func(t, tcg_env, t); 4382e41716beSRichard Henderson gen_store_fpr_Q(dc, a->rd, t); 4383c995216bSRichard Henderson return advance_pc(dc); 4384c995216bSRichard Henderson } 4385c995216bSRichard Henderson 4386c995216bSRichard Henderson TRANS(FSQRTq, ALL, do_env_qq, a, gen_helper_fsqrtq) 4387c995216bSRichard Henderson 4388bd9c5c42SRichard Henderson static bool do_env_fq(DisasContext *dc, arg_r_r *a, 4389d81e3efeSRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i128)) 4390bd9c5c42SRichard Henderson { 4391d81e3efeSRichard Henderson TCGv_i128 src; 4392bd9c5c42SRichard Henderson TCGv_i32 dst; 4393bd9c5c42SRichard Henderson 4394bd9c5c42SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4395bd9c5c42SRichard Henderson return true; 4396bd9c5c42SRichard Henderson } 4397bd9c5c42SRichard Henderson if (gen_trap_float128(dc)) { 4398bd9c5c42SRichard Henderson return true; 4399bd9c5c42SRichard Henderson } 4400bd9c5c42SRichard Henderson 4401d81e3efeSRichard Henderson src = gen_load_fpr_Q(dc, a->rs); 4402388a6465SRichard Henderson dst = tcg_temp_new_i32(); 4403d81e3efeSRichard Henderson func(dst, tcg_env, src); 4404bd9c5c42SRichard Henderson gen_store_fpr_F(dc, a->rd, dst); 4405bd9c5c42SRichard Henderson return advance_pc(dc); 4406bd9c5c42SRichard Henderson } 4407bd9c5c42SRichard Henderson 4408bd9c5c42SRichard Henderson TRANS(FqTOs, ALL, do_env_fq, a, gen_helper_fqtos) 4409bd9c5c42SRichard Henderson TRANS(FqTOi, ALL, do_env_fq, a, gen_helper_fqtoi) 4410bd9c5c42SRichard Henderson 44111617586fSRichard Henderson static bool do_env_dq(DisasContext *dc, arg_r_r *a, 441225a5769eSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i128)) 44131617586fSRichard Henderson { 441425a5769eSRichard Henderson TCGv_i128 src; 44151617586fSRichard Henderson TCGv_i64 dst; 44161617586fSRichard Henderson 44171617586fSRichard Henderson if (gen_trap_ifnofpu(dc)) { 44181617586fSRichard Henderson return true; 44191617586fSRichard Henderson } 44201617586fSRichard Henderson if (gen_trap_float128(dc)) { 44211617586fSRichard Henderson return true; 44221617586fSRichard Henderson } 44231617586fSRichard Henderson 442425a5769eSRichard Henderson src = gen_load_fpr_Q(dc, a->rs); 44251617586fSRichard Henderson dst = gen_dest_fpr_D(dc, a->rd); 442625a5769eSRichard Henderson func(dst, tcg_env, src); 44271617586fSRichard Henderson gen_store_fpr_D(dc, a->rd, dst); 44281617586fSRichard Henderson return advance_pc(dc); 44291617586fSRichard Henderson } 44301617586fSRichard Henderson 44311617586fSRichard Henderson TRANS(FqTOd, ALL, do_env_dq, a, gen_helper_fqtod) 44321617586fSRichard Henderson TRANS(FqTOx, 64, do_env_dq, a, gen_helper_fqtox) 44331617586fSRichard Henderson 443413ebcc77SRichard Henderson static bool do_env_qf(DisasContext *dc, arg_r_r *a, 44350b2a61ccSRichard Henderson void (*func)(TCGv_i128, TCGv_env, TCGv_i32)) 443613ebcc77SRichard Henderson { 443713ebcc77SRichard Henderson TCGv_i32 src; 44380b2a61ccSRichard Henderson TCGv_i128 dst; 443913ebcc77SRichard Henderson 444013ebcc77SRichard Henderson if (gen_trap_ifnofpu(dc)) { 444113ebcc77SRichard Henderson return true; 444213ebcc77SRichard Henderson } 444313ebcc77SRichard Henderson if (gen_trap_float128(dc)) { 444413ebcc77SRichard Henderson return true; 444513ebcc77SRichard Henderson } 444613ebcc77SRichard Henderson 444713ebcc77SRichard Henderson src = gen_load_fpr_F(dc, a->rs); 44480b2a61ccSRichard Henderson dst = tcg_temp_new_i128(); 44490b2a61ccSRichard Henderson func(dst, tcg_env, src); 44500b2a61ccSRichard Henderson gen_store_fpr_Q(dc, a->rd, dst); 445113ebcc77SRichard Henderson return advance_pc(dc); 445213ebcc77SRichard Henderson } 445313ebcc77SRichard Henderson 445413ebcc77SRichard Henderson TRANS(FiTOq, ALL, do_env_qf, a, gen_helper_fitoq) 445513ebcc77SRichard Henderson TRANS(FsTOq, ALL, do_env_qf, a, gen_helper_fstoq) 445613ebcc77SRichard Henderson 44577b8e3e1aSRichard Henderson static bool do_env_qd(DisasContext *dc, arg_r_r *a, 4458fdc50716SRichard Henderson void (*func)(TCGv_i128, TCGv_env, TCGv_i64)) 44597b8e3e1aSRichard Henderson { 44607b8e3e1aSRichard Henderson TCGv_i64 src; 4461fdc50716SRichard Henderson TCGv_i128 dst; 44627b8e3e1aSRichard Henderson 44637b8e3e1aSRichard Henderson if (gen_trap_ifnofpu(dc)) { 44647b8e3e1aSRichard Henderson return true; 44657b8e3e1aSRichard Henderson } 44667b8e3e1aSRichard Henderson if (gen_trap_float128(dc)) { 44677b8e3e1aSRichard Henderson return true; 44687b8e3e1aSRichard Henderson } 44697b8e3e1aSRichard Henderson 44707b8e3e1aSRichard Henderson src = gen_load_fpr_D(dc, a->rs); 4471fdc50716SRichard Henderson dst = tcg_temp_new_i128(); 4472fdc50716SRichard Henderson func(dst, tcg_env, src); 4473fdc50716SRichard Henderson gen_store_fpr_Q(dc, a->rd, dst); 44747b8e3e1aSRichard Henderson return advance_pc(dc); 44757b8e3e1aSRichard Henderson } 44767b8e3e1aSRichard Henderson 44777b8e3e1aSRichard Henderson TRANS(FdTOq, ALL, do_env_qd, a, gen_helper_fdtoq) 44787b8e3e1aSRichard Henderson TRANS(FxTOq, 64, do_env_qd, a, gen_helper_fxtoq) 44797b8e3e1aSRichard Henderson 44807f10b52fSRichard Henderson static bool do_fff(DisasContext *dc, arg_r_r_r *a, 44817f10b52fSRichard Henderson void (*func)(TCGv_i32, TCGv_i32, TCGv_i32)) 44827f10b52fSRichard Henderson { 44837f10b52fSRichard Henderson TCGv_i32 src1, src2; 44847f10b52fSRichard Henderson 44857f10b52fSRichard Henderson if (gen_trap_ifnofpu(dc)) { 44867f10b52fSRichard Henderson return true; 44877f10b52fSRichard Henderson } 44887f10b52fSRichard Henderson 44897f10b52fSRichard Henderson src1 = gen_load_fpr_F(dc, a->rs1); 44907f10b52fSRichard Henderson src2 = gen_load_fpr_F(dc, a->rs2); 44917f10b52fSRichard Henderson func(src1, src1, src2); 44927f10b52fSRichard Henderson gen_store_fpr_F(dc, a->rd, src1); 44937f10b52fSRichard Henderson return advance_pc(dc); 44947f10b52fSRichard Henderson } 44957f10b52fSRichard Henderson 44967f10b52fSRichard Henderson TRANS(FPADD16s, VIS1, do_fff, a, tcg_gen_vec_add16_i32) 44977f10b52fSRichard Henderson TRANS(FPADD32s, VIS1, do_fff, a, tcg_gen_add_i32) 44987f10b52fSRichard Henderson TRANS(FPSUB16s, VIS1, do_fff, a, tcg_gen_vec_sub16_i32) 44997f10b52fSRichard Henderson TRANS(FPSUB32s, VIS1, do_fff, a, tcg_gen_sub_i32) 45007f10b52fSRichard Henderson TRANS(FNORs, VIS1, do_fff, a, tcg_gen_nor_i32) 45017f10b52fSRichard Henderson TRANS(FANDNOTs, VIS1, do_fff, a, tcg_gen_andc_i32) 45027f10b52fSRichard Henderson TRANS(FXORs, VIS1, do_fff, a, tcg_gen_xor_i32) 45037f10b52fSRichard Henderson TRANS(FNANDs, VIS1, do_fff, a, tcg_gen_nand_i32) 45047f10b52fSRichard Henderson TRANS(FANDs, VIS1, do_fff, a, tcg_gen_and_i32) 45057f10b52fSRichard Henderson TRANS(FXNORs, VIS1, do_fff, a, tcg_gen_eqv_i32) 45067f10b52fSRichard Henderson TRANS(FORNOTs, VIS1, do_fff, a, tcg_gen_orc_i32) 45077f10b52fSRichard Henderson TRANS(FORs, VIS1, do_fff, a, tcg_gen_or_i32) 45087f10b52fSRichard Henderson 4509c1514961SRichard Henderson static bool do_env_fff(DisasContext *dc, arg_r_r_r *a, 4510c1514961SRichard Henderson void (*func)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32)) 4511c1514961SRichard Henderson { 4512c1514961SRichard Henderson TCGv_i32 src1, src2; 4513c1514961SRichard Henderson 4514c1514961SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4515c1514961SRichard Henderson return true; 4516c1514961SRichard Henderson } 4517c1514961SRichard Henderson 4518c1514961SRichard Henderson src1 = gen_load_fpr_F(dc, a->rs1); 4519c1514961SRichard Henderson src2 = gen_load_fpr_F(dc, a->rs2); 4520c1514961SRichard Henderson func(src1, tcg_env, src1, src2); 4521c1514961SRichard Henderson gen_store_fpr_F(dc, a->rd, src1); 4522c1514961SRichard Henderson return advance_pc(dc); 4523c1514961SRichard Henderson } 4524c1514961SRichard Henderson 4525c1514961SRichard Henderson TRANS(FADDs, ALL, do_env_fff, a, gen_helper_fadds) 4526c1514961SRichard Henderson TRANS(FSUBs, ALL, do_env_fff, a, gen_helper_fsubs) 4527c1514961SRichard Henderson TRANS(FMULs, ALL, do_env_fff, a, gen_helper_fmuls) 4528c1514961SRichard Henderson TRANS(FDIVs, ALL, do_env_fff, a, gen_helper_fdivs) 4529c1514961SRichard Henderson 4530e06c9f83SRichard Henderson static bool do_ddd(DisasContext *dc, arg_r_r_r *a, 4531e06c9f83SRichard Henderson void (*func)(TCGv_i64, TCGv_i64, TCGv_i64)) 4532e06c9f83SRichard Henderson { 4533e06c9f83SRichard Henderson TCGv_i64 dst, src1, src2; 4534e06c9f83SRichard Henderson 4535e06c9f83SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4536e06c9f83SRichard Henderson return true; 4537e06c9f83SRichard Henderson } 4538e06c9f83SRichard Henderson 4539e06c9f83SRichard Henderson dst = gen_dest_fpr_D(dc, a->rd); 4540e06c9f83SRichard Henderson src1 = gen_load_fpr_D(dc, a->rs1); 4541e06c9f83SRichard Henderson src2 = gen_load_fpr_D(dc, a->rs2); 4542e06c9f83SRichard Henderson func(dst, src1, src2); 4543e06c9f83SRichard Henderson gen_store_fpr_D(dc, a->rd, dst); 4544e06c9f83SRichard Henderson return advance_pc(dc); 4545e06c9f83SRichard Henderson } 4546e06c9f83SRichard Henderson 4547e06c9f83SRichard Henderson TRANS(FMUL8x16, VIS1, do_ddd, a, gen_helper_fmul8x16) 4548e06c9f83SRichard Henderson TRANS(FMUL8x16AU, VIS1, do_ddd, a, gen_helper_fmul8x16au) 4549e06c9f83SRichard Henderson TRANS(FMUL8x16AL, VIS1, do_ddd, a, gen_helper_fmul8x16al) 4550e06c9f83SRichard Henderson TRANS(FMUL8SUx16, VIS1, do_ddd, a, gen_helper_fmul8sux16) 4551e06c9f83SRichard Henderson TRANS(FMUL8ULx16, VIS1, do_ddd, a, gen_helper_fmul8ulx16) 4552e06c9f83SRichard Henderson TRANS(FMULD8SUx16, VIS1, do_ddd, a, gen_helper_fmuld8sux16) 4553e06c9f83SRichard Henderson TRANS(FMULD8ULx16, VIS1, do_ddd, a, gen_helper_fmuld8ulx16) 4554e06c9f83SRichard Henderson TRANS(FPMERGE, VIS1, do_ddd, a, gen_helper_fpmerge) 4555e06c9f83SRichard Henderson TRANS(FEXPAND, VIS1, do_ddd, a, gen_helper_fexpand) 4556e06c9f83SRichard Henderson 4557e06c9f83SRichard Henderson TRANS(FPADD16, VIS1, do_ddd, a, tcg_gen_vec_add16_i64) 4558e06c9f83SRichard Henderson TRANS(FPADD32, VIS1, do_ddd, a, tcg_gen_vec_add32_i64) 4559e06c9f83SRichard Henderson TRANS(FPSUB16, VIS1, do_ddd, a, tcg_gen_vec_sub16_i64) 4560e06c9f83SRichard Henderson TRANS(FPSUB32, VIS1, do_ddd, a, tcg_gen_vec_sub32_i64) 4561e06c9f83SRichard Henderson TRANS(FNORd, VIS1, do_ddd, a, tcg_gen_nor_i64) 4562e06c9f83SRichard Henderson TRANS(FANDNOTd, VIS1, do_ddd, a, tcg_gen_andc_i64) 4563e06c9f83SRichard Henderson TRANS(FXORd, VIS1, do_ddd, a, tcg_gen_xor_i64) 4564e06c9f83SRichard Henderson TRANS(FNANDd, VIS1, do_ddd, a, tcg_gen_nand_i64) 4565e06c9f83SRichard Henderson TRANS(FANDd, VIS1, do_ddd, a, tcg_gen_and_i64) 4566e06c9f83SRichard Henderson TRANS(FXNORd, VIS1, do_ddd, a, tcg_gen_eqv_i64) 4567e06c9f83SRichard Henderson TRANS(FORNOTd, VIS1, do_ddd, a, tcg_gen_orc_i64) 4568e06c9f83SRichard Henderson TRANS(FORd, VIS1, do_ddd, a, tcg_gen_or_i64) 4569e06c9f83SRichard Henderson 45704b6edc0aSRichard Henderson TRANS(FPACK32, VIS1, do_ddd, a, gen_op_fpack32) 45714b6edc0aSRichard Henderson TRANS(FALIGNDATAg, VIS1, do_ddd, a, gen_op_faligndata) 45724b6edc0aSRichard Henderson TRANS(BSHUFFLE, VIS2, do_ddd, a, gen_op_bshuffle) 45734b6edc0aSRichard Henderson 4574e2fa6bd1SRichard Henderson static bool do_rdd(DisasContext *dc, arg_r_r_r *a, 4575e2fa6bd1SRichard Henderson void (*func)(TCGv, TCGv_i64, TCGv_i64)) 4576e2fa6bd1SRichard Henderson { 4577e2fa6bd1SRichard Henderson TCGv_i64 src1, src2; 4578e2fa6bd1SRichard Henderson TCGv dst; 4579e2fa6bd1SRichard Henderson 4580e2fa6bd1SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4581e2fa6bd1SRichard Henderson return true; 4582e2fa6bd1SRichard Henderson } 4583e2fa6bd1SRichard Henderson 4584e2fa6bd1SRichard Henderson dst = gen_dest_gpr(dc, a->rd); 4585e2fa6bd1SRichard Henderson src1 = gen_load_fpr_D(dc, a->rs1); 4586e2fa6bd1SRichard Henderson src2 = gen_load_fpr_D(dc, a->rs2); 4587e2fa6bd1SRichard Henderson func(dst, src1, src2); 4588e2fa6bd1SRichard Henderson gen_store_gpr(dc, a->rd, dst); 4589e2fa6bd1SRichard Henderson return advance_pc(dc); 4590e2fa6bd1SRichard Henderson } 4591e2fa6bd1SRichard Henderson 4592e2fa6bd1SRichard Henderson TRANS(FPCMPLE16, VIS1, do_rdd, a, gen_helper_fcmple16) 4593e2fa6bd1SRichard Henderson TRANS(FPCMPNE16, VIS1, do_rdd, a, gen_helper_fcmpne16) 4594e2fa6bd1SRichard Henderson TRANS(FPCMPGT16, VIS1, do_rdd, a, gen_helper_fcmpgt16) 4595e2fa6bd1SRichard Henderson TRANS(FPCMPEQ16, VIS1, do_rdd, a, gen_helper_fcmpeq16) 4596e2fa6bd1SRichard Henderson 4597e2fa6bd1SRichard Henderson TRANS(FPCMPLE32, VIS1, do_rdd, a, gen_helper_fcmple32) 4598e2fa6bd1SRichard Henderson TRANS(FPCMPNE32, VIS1, do_rdd, a, gen_helper_fcmpne32) 4599e2fa6bd1SRichard Henderson TRANS(FPCMPGT32, VIS1, do_rdd, a, gen_helper_fcmpgt32) 4600e2fa6bd1SRichard Henderson TRANS(FPCMPEQ32, VIS1, do_rdd, a, gen_helper_fcmpeq32) 4601e2fa6bd1SRichard Henderson 4602f2a59b0aSRichard Henderson static bool do_env_ddd(DisasContext *dc, arg_r_r_r *a, 4603f2a59b0aSRichard Henderson void (*func)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64)) 4604f2a59b0aSRichard Henderson { 4605f2a59b0aSRichard Henderson TCGv_i64 dst, src1, src2; 4606f2a59b0aSRichard Henderson 4607f2a59b0aSRichard Henderson if (gen_trap_ifnofpu(dc)) { 4608f2a59b0aSRichard Henderson return true; 4609f2a59b0aSRichard Henderson } 4610f2a59b0aSRichard Henderson 4611f2a59b0aSRichard Henderson dst = gen_dest_fpr_D(dc, a->rd); 4612f2a59b0aSRichard Henderson src1 = gen_load_fpr_D(dc, a->rs1); 4613f2a59b0aSRichard Henderson src2 = gen_load_fpr_D(dc, a->rs2); 4614f2a59b0aSRichard Henderson func(dst, tcg_env, src1, src2); 4615f2a59b0aSRichard Henderson gen_store_fpr_D(dc, a->rd, dst); 4616f2a59b0aSRichard Henderson return advance_pc(dc); 4617f2a59b0aSRichard Henderson } 4618f2a59b0aSRichard Henderson 4619f2a59b0aSRichard Henderson TRANS(FADDd, ALL, do_env_ddd, a, gen_helper_faddd) 4620f2a59b0aSRichard Henderson TRANS(FSUBd, ALL, do_env_ddd, a, gen_helper_fsubd) 4621f2a59b0aSRichard Henderson TRANS(FMULd, ALL, do_env_ddd, a, gen_helper_fmuld) 4622f2a59b0aSRichard Henderson TRANS(FDIVd, ALL, do_env_ddd, a, gen_helper_fdivd) 4623f2a59b0aSRichard Henderson 4624ff4c711bSRichard Henderson static bool trans_FsMULd(DisasContext *dc, arg_r_r_r *a) 4625ff4c711bSRichard Henderson { 4626ff4c711bSRichard Henderson TCGv_i64 dst; 4627ff4c711bSRichard Henderson TCGv_i32 src1, src2; 4628ff4c711bSRichard Henderson 4629ff4c711bSRichard Henderson if (gen_trap_ifnofpu(dc)) { 4630ff4c711bSRichard Henderson return true; 4631ff4c711bSRichard Henderson } 4632ff4c711bSRichard Henderson if (!(dc->def->features & CPU_FEATURE_FSMULD)) { 4633ff4c711bSRichard Henderson return raise_unimpfpop(dc); 4634ff4c711bSRichard Henderson } 4635ff4c711bSRichard Henderson 4636ff4c711bSRichard Henderson dst = gen_dest_fpr_D(dc, a->rd); 4637ff4c711bSRichard Henderson src1 = gen_load_fpr_F(dc, a->rs1); 4638ff4c711bSRichard Henderson src2 = gen_load_fpr_F(dc, a->rs2); 4639ff4c711bSRichard Henderson gen_helper_fsmuld(dst, tcg_env, src1, src2); 4640ff4c711bSRichard Henderson gen_store_fpr_D(dc, a->rd, dst); 4641ff4c711bSRichard Henderson return advance_pc(dc); 4642ff4c711bSRichard Henderson } 4643ff4c711bSRichard Henderson 4644afb04344SRichard Henderson static bool do_dddd(DisasContext *dc, arg_r_r_r *a, 4645afb04344SRichard Henderson void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) 4646afb04344SRichard Henderson { 4647afb04344SRichard Henderson TCGv_i64 dst, src0, src1, src2; 4648afb04344SRichard Henderson 4649afb04344SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4650afb04344SRichard Henderson return true; 4651afb04344SRichard Henderson } 4652afb04344SRichard Henderson 4653afb04344SRichard Henderson dst = gen_dest_fpr_D(dc, a->rd); 4654afb04344SRichard Henderson src0 = gen_load_fpr_D(dc, a->rd); 4655afb04344SRichard Henderson src1 = gen_load_fpr_D(dc, a->rs1); 4656afb04344SRichard Henderson src2 = gen_load_fpr_D(dc, a->rs2); 4657afb04344SRichard Henderson func(dst, src0, src1, src2); 4658afb04344SRichard Henderson gen_store_fpr_D(dc, a->rd, dst); 4659afb04344SRichard Henderson return advance_pc(dc); 4660afb04344SRichard Henderson } 4661afb04344SRichard Henderson 4662afb04344SRichard Henderson TRANS(PDIST, VIS1, do_dddd, a, gen_helper_pdist) 4663afb04344SRichard Henderson 4664a4056239SRichard Henderson static bool do_env_qqq(DisasContext *dc, arg_r_r_r *a, 466516bedf89SRichard Henderson void (*func)(TCGv_i128, TCGv_env, TCGv_i128, TCGv_i128)) 4666a4056239SRichard Henderson { 466716bedf89SRichard Henderson TCGv_i128 src1, src2; 466816bedf89SRichard Henderson 4669a4056239SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4670a4056239SRichard Henderson return true; 4671a4056239SRichard Henderson } 4672a4056239SRichard Henderson if (gen_trap_float128(dc)) { 4673a4056239SRichard Henderson return true; 4674a4056239SRichard Henderson } 4675a4056239SRichard Henderson 467616bedf89SRichard Henderson src1 = gen_load_fpr_Q(dc, a->rs1); 467716bedf89SRichard Henderson src2 = gen_load_fpr_Q(dc, a->rs2); 467816bedf89SRichard Henderson func(src1, tcg_env, src1, src2); 467916bedf89SRichard Henderson gen_store_fpr_Q(dc, a->rd, src1); 4680a4056239SRichard Henderson return advance_pc(dc); 4681a4056239SRichard Henderson } 4682a4056239SRichard Henderson 4683a4056239SRichard Henderson TRANS(FADDq, ALL, do_env_qqq, a, gen_helper_faddq) 4684a4056239SRichard Henderson TRANS(FSUBq, ALL, do_env_qqq, a, gen_helper_fsubq) 4685a4056239SRichard Henderson TRANS(FMULq, ALL, do_env_qqq, a, gen_helper_fmulq) 4686a4056239SRichard Henderson TRANS(FDIVq, ALL, do_env_qqq, a, gen_helper_fdivq) 4687a4056239SRichard Henderson 46885e3b17bbSRichard Henderson static bool trans_FdMULq(DisasContext *dc, arg_r_r_r *a) 46895e3b17bbSRichard Henderson { 46905e3b17bbSRichard Henderson TCGv_i64 src1, src2; 4691ba21dc99SRichard Henderson TCGv_i128 dst; 46925e3b17bbSRichard Henderson 46935e3b17bbSRichard Henderson if (gen_trap_ifnofpu(dc)) { 46945e3b17bbSRichard Henderson return true; 46955e3b17bbSRichard Henderson } 46965e3b17bbSRichard Henderson if (gen_trap_float128(dc)) { 46975e3b17bbSRichard Henderson return true; 46985e3b17bbSRichard Henderson } 46995e3b17bbSRichard Henderson 47005e3b17bbSRichard Henderson src1 = gen_load_fpr_D(dc, a->rs1); 47015e3b17bbSRichard Henderson src2 = gen_load_fpr_D(dc, a->rs2); 4702ba21dc99SRichard Henderson dst = tcg_temp_new_i128(); 4703ba21dc99SRichard Henderson gen_helper_fdmulq(dst, tcg_env, src1, src2); 4704ba21dc99SRichard Henderson gen_store_fpr_Q(dc, a->rd, dst); 47055e3b17bbSRichard Henderson return advance_pc(dc); 47065e3b17bbSRichard Henderson } 47075e3b17bbSRichard Henderson 4708f7ec8155SRichard Henderson static bool do_fmovr(DisasContext *dc, arg_FMOVRs *a, bool is_128, 4709f7ec8155SRichard Henderson void (*func)(DisasContext *, DisasCompare *, int, int)) 4710f7ec8155SRichard Henderson { 4711f7ec8155SRichard Henderson DisasCompare cmp; 4712f7ec8155SRichard Henderson 47132c4f56c9SRichard Henderson if (!gen_compare_reg(&cmp, a->cond, gen_load_gpr(dc, a->rs1))) { 47142c4f56c9SRichard Henderson return false; 47152c4f56c9SRichard Henderson } 4716f7ec8155SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4717f7ec8155SRichard Henderson return true; 4718f7ec8155SRichard Henderson } 4719f7ec8155SRichard Henderson if (is_128 && gen_trap_float128(dc)) { 4720f7ec8155SRichard Henderson return true; 4721f7ec8155SRichard Henderson } 4722f7ec8155SRichard Henderson 4723f7ec8155SRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 4724f7ec8155SRichard Henderson func(dc, &cmp, a->rd, a->rs2); 4725f7ec8155SRichard Henderson return advance_pc(dc); 4726f7ec8155SRichard Henderson } 4727f7ec8155SRichard Henderson 4728f7ec8155SRichard Henderson TRANS(FMOVRs, 64, do_fmovr, a, false, gen_fmovs) 4729f7ec8155SRichard Henderson TRANS(FMOVRd, 64, do_fmovr, a, false, gen_fmovd) 4730f7ec8155SRichard Henderson TRANS(FMOVRq, 64, do_fmovr, a, true, gen_fmovq) 4731f7ec8155SRichard Henderson 4732f7ec8155SRichard Henderson static bool do_fmovcc(DisasContext *dc, arg_FMOVscc *a, bool is_128, 4733f7ec8155SRichard Henderson void (*func)(DisasContext *, DisasCompare *, int, int)) 4734f7ec8155SRichard Henderson { 4735f7ec8155SRichard Henderson DisasCompare cmp; 4736f7ec8155SRichard Henderson 4737f7ec8155SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4738f7ec8155SRichard Henderson return true; 4739f7ec8155SRichard Henderson } 4740f7ec8155SRichard Henderson if (is_128 && gen_trap_float128(dc)) { 4741f7ec8155SRichard Henderson return true; 4742f7ec8155SRichard Henderson } 4743f7ec8155SRichard Henderson 4744f7ec8155SRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 4745f7ec8155SRichard Henderson gen_compare(&cmp, a->cc, a->cond, dc); 4746f7ec8155SRichard Henderson func(dc, &cmp, a->rd, a->rs2); 4747f7ec8155SRichard Henderson return advance_pc(dc); 4748f7ec8155SRichard Henderson } 4749f7ec8155SRichard Henderson 4750f7ec8155SRichard Henderson TRANS(FMOVscc, 64, do_fmovcc, a, false, gen_fmovs) 4751f7ec8155SRichard Henderson TRANS(FMOVdcc, 64, do_fmovcc, a, false, gen_fmovd) 4752f7ec8155SRichard Henderson TRANS(FMOVqcc, 64, do_fmovcc, a, true, gen_fmovq) 4753f7ec8155SRichard Henderson 4754f7ec8155SRichard Henderson static bool do_fmovfcc(DisasContext *dc, arg_FMOVsfcc *a, bool is_128, 4755f7ec8155SRichard Henderson void (*func)(DisasContext *, DisasCompare *, int, int)) 4756f7ec8155SRichard Henderson { 4757f7ec8155SRichard Henderson DisasCompare cmp; 4758f7ec8155SRichard Henderson 4759f7ec8155SRichard Henderson if (gen_trap_ifnofpu(dc)) { 4760f7ec8155SRichard Henderson return true; 4761f7ec8155SRichard Henderson } 4762f7ec8155SRichard Henderson if (is_128 && gen_trap_float128(dc)) { 4763f7ec8155SRichard Henderson return true; 4764f7ec8155SRichard Henderson } 4765f7ec8155SRichard Henderson 4766f7ec8155SRichard Henderson gen_op_clear_ieee_excp_and_FTT(); 4767f7ec8155SRichard Henderson gen_fcompare(&cmp, a->cc, a->cond); 4768f7ec8155SRichard Henderson func(dc, &cmp, a->rd, a->rs2); 4769f7ec8155SRichard Henderson return advance_pc(dc); 4770f7ec8155SRichard Henderson } 4771f7ec8155SRichard Henderson 4772f7ec8155SRichard Henderson TRANS(FMOVsfcc, 64, do_fmovfcc, a, false, gen_fmovs) 4773f7ec8155SRichard Henderson TRANS(FMOVdfcc, 64, do_fmovfcc, a, false, gen_fmovd) 4774f7ec8155SRichard Henderson TRANS(FMOVqfcc, 64, do_fmovfcc, a, true, gen_fmovq) 4775f7ec8155SRichard Henderson 477640f9ad21SRichard Henderson static bool do_fcmps(DisasContext *dc, arg_FCMPs *a, bool e) 477740f9ad21SRichard Henderson { 477840f9ad21SRichard Henderson TCGv_i32 src1, src2; 477940f9ad21SRichard Henderson 478040f9ad21SRichard Henderson if (avail_32(dc) && a->cc != 0) { 478140f9ad21SRichard Henderson return false; 478240f9ad21SRichard Henderson } 478340f9ad21SRichard Henderson if (gen_trap_ifnofpu(dc)) { 478440f9ad21SRichard Henderson return true; 478540f9ad21SRichard Henderson } 478640f9ad21SRichard Henderson 478740f9ad21SRichard Henderson src1 = gen_load_fpr_F(dc, a->rs1); 478840f9ad21SRichard Henderson src2 = gen_load_fpr_F(dc, a->rs2); 478940f9ad21SRichard Henderson if (e) { 4790d8c5b92fSRichard Henderson gen_helper_fcmpes(cpu_fcc[a->cc], tcg_env, src1, src2); 479140f9ad21SRichard Henderson } else { 4792d8c5b92fSRichard Henderson gen_helper_fcmps(cpu_fcc[a->cc], tcg_env, src1, src2); 479340f9ad21SRichard Henderson } 479440f9ad21SRichard Henderson return advance_pc(dc); 479540f9ad21SRichard Henderson } 479640f9ad21SRichard Henderson 479740f9ad21SRichard Henderson TRANS(FCMPs, ALL, do_fcmps, a, false) 479840f9ad21SRichard Henderson TRANS(FCMPEs, ALL, do_fcmps, a, true) 479940f9ad21SRichard Henderson 480040f9ad21SRichard Henderson static bool do_fcmpd(DisasContext *dc, arg_FCMPd *a, bool e) 480140f9ad21SRichard Henderson { 480240f9ad21SRichard Henderson TCGv_i64 src1, src2; 480340f9ad21SRichard Henderson 480440f9ad21SRichard Henderson if (avail_32(dc) && a->cc != 0) { 480540f9ad21SRichard Henderson return false; 480640f9ad21SRichard Henderson } 480740f9ad21SRichard Henderson if (gen_trap_ifnofpu(dc)) { 480840f9ad21SRichard Henderson return true; 480940f9ad21SRichard Henderson } 481040f9ad21SRichard Henderson 481140f9ad21SRichard Henderson src1 = gen_load_fpr_D(dc, a->rs1); 481240f9ad21SRichard Henderson src2 = gen_load_fpr_D(dc, a->rs2); 481340f9ad21SRichard Henderson if (e) { 4814d8c5b92fSRichard Henderson gen_helper_fcmped(cpu_fcc[a->cc], tcg_env, src1, src2); 481540f9ad21SRichard Henderson } else { 4816d8c5b92fSRichard Henderson gen_helper_fcmpd(cpu_fcc[a->cc], tcg_env, src1, src2); 481740f9ad21SRichard Henderson } 481840f9ad21SRichard Henderson return advance_pc(dc); 481940f9ad21SRichard Henderson } 482040f9ad21SRichard Henderson 482140f9ad21SRichard Henderson TRANS(FCMPd, ALL, do_fcmpd, a, false) 482240f9ad21SRichard Henderson TRANS(FCMPEd, ALL, do_fcmpd, a, true) 482340f9ad21SRichard Henderson 482440f9ad21SRichard Henderson static bool do_fcmpq(DisasContext *dc, arg_FCMPq *a, bool e) 482540f9ad21SRichard Henderson { 4826f3ceafadSRichard Henderson TCGv_i128 src1, src2; 4827f3ceafadSRichard Henderson 482840f9ad21SRichard Henderson if (avail_32(dc) && a->cc != 0) { 482940f9ad21SRichard Henderson return false; 483040f9ad21SRichard Henderson } 483140f9ad21SRichard Henderson if (gen_trap_ifnofpu(dc)) { 483240f9ad21SRichard Henderson return true; 483340f9ad21SRichard Henderson } 483440f9ad21SRichard Henderson if (gen_trap_float128(dc)) { 483540f9ad21SRichard Henderson return true; 483640f9ad21SRichard Henderson } 483740f9ad21SRichard Henderson 4838f3ceafadSRichard Henderson src1 = gen_load_fpr_Q(dc, a->rs1); 4839f3ceafadSRichard Henderson src2 = gen_load_fpr_Q(dc, a->rs2); 484040f9ad21SRichard Henderson if (e) { 4841d8c5b92fSRichard Henderson gen_helper_fcmpeq(cpu_fcc[a->cc], tcg_env, src1, src2); 484240f9ad21SRichard Henderson } else { 4843d8c5b92fSRichard Henderson gen_helper_fcmpq(cpu_fcc[a->cc], tcg_env, src1, src2); 484440f9ad21SRichard Henderson } 484540f9ad21SRichard Henderson return advance_pc(dc); 484640f9ad21SRichard Henderson } 484740f9ad21SRichard Henderson 484840f9ad21SRichard Henderson TRANS(FCMPq, ALL, do_fcmpq, a, false) 484940f9ad21SRichard Henderson TRANS(FCMPEq, ALL, do_fcmpq, a, true) 485040f9ad21SRichard Henderson 48516e61bc94SEmilio G. Cota static void sparc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 4852fcf5ef2aSThomas Huth { 48536e61bc94SEmilio G. Cota DisasContext *dc = container_of(dcbase, DisasContext, base); 4854b77af26eSRichard Henderson CPUSPARCState *env = cpu_env(cs); 48556e61bc94SEmilio G. Cota int bound; 4856af00be49SEmilio G. Cota 4857af00be49SEmilio G. Cota dc->pc = dc->base.pc_first; 48586e61bc94SEmilio G. Cota dc->npc = (target_ulong)dc->base.tb->cs_base; 48596e61bc94SEmilio G. Cota dc->mem_idx = dc->base.tb->flags & TB_FLAG_MMU_MASK; 4860576e1c4cSIgor Mammedov dc->def = &env->def; 48616e61bc94SEmilio G. Cota dc->fpu_enabled = tb_fpu_enabled(dc->base.tb->flags); 48626e61bc94SEmilio G. Cota dc->address_mask_32bit = tb_am_enabled(dc->base.tb->flags); 4863c9b459aaSArtyom Tarasenko #ifndef CONFIG_USER_ONLY 48646e61bc94SEmilio G. Cota dc->supervisor = (dc->base.tb->flags & TB_FLAG_SUPER) != 0; 4865c9b459aaSArtyom Tarasenko #endif 4866fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 4867fcf5ef2aSThomas Huth dc->fprs_dirty = 0; 48686e61bc94SEmilio G. Cota dc->asi = (dc->base.tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff; 4869c9b459aaSArtyom Tarasenko #ifndef CONFIG_USER_ONLY 48706e61bc94SEmilio G. Cota dc->hypervisor = (dc->base.tb->flags & TB_FLAG_HYPER) != 0; 4871c9b459aaSArtyom Tarasenko #endif 4872fcf5ef2aSThomas Huth #endif 48736e61bc94SEmilio G. Cota /* 48746e61bc94SEmilio G. Cota * if we reach a page boundary, we stop generation so that the 48756e61bc94SEmilio G. Cota * PC of a TT_TFAULT exception is always in the right page 48766e61bc94SEmilio G. Cota */ 48776e61bc94SEmilio G. Cota bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 48786e61bc94SEmilio G. Cota dc->base.max_insns = MIN(dc->base.max_insns, bound); 4879af00be49SEmilio G. Cota } 4880fcf5ef2aSThomas Huth 48816e61bc94SEmilio G. Cota static void sparc_tr_tb_start(DisasContextBase *db, CPUState *cs) 48826e61bc94SEmilio G. Cota { 48836e61bc94SEmilio G. Cota } 48846e61bc94SEmilio G. Cota 48856e61bc94SEmilio G. Cota static void sparc_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 48866e61bc94SEmilio G. Cota { 48876e61bc94SEmilio G. Cota DisasContext *dc = container_of(dcbase, DisasContext, base); 4888633c4283SRichard Henderson target_ulong npc = dc->npc; 48896e61bc94SEmilio G. Cota 4890633c4283SRichard Henderson if (npc & 3) { 4891633c4283SRichard Henderson switch (npc) { 4892633c4283SRichard Henderson case JUMP_PC: 4893fcf5ef2aSThomas Huth assert(dc->jump_pc[1] == dc->pc + 4); 4894633c4283SRichard Henderson npc = dc->jump_pc[0] | JUMP_PC; 4895633c4283SRichard Henderson break; 4896633c4283SRichard Henderson case DYNAMIC_PC: 4897633c4283SRichard Henderson case DYNAMIC_PC_LOOKUP: 4898633c4283SRichard Henderson npc = DYNAMIC_PC; 4899633c4283SRichard Henderson break; 4900633c4283SRichard Henderson default: 4901633c4283SRichard Henderson g_assert_not_reached(); 4902fcf5ef2aSThomas Huth } 49036e61bc94SEmilio G. Cota } 4904633c4283SRichard Henderson tcg_gen_insn_start(dc->pc, npc); 4905633c4283SRichard Henderson } 4906fcf5ef2aSThomas Huth 49076e61bc94SEmilio G. Cota static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 49086e61bc94SEmilio G. Cota { 49096e61bc94SEmilio G. Cota DisasContext *dc = container_of(dcbase, DisasContext, base); 4910b77af26eSRichard Henderson CPUSPARCState *env = cpu_env(cs); 49116e61bc94SEmilio G. Cota unsigned int insn; 4912fcf5ef2aSThomas Huth 49134e116893SIlya Leoshkevich insn = translator_ldl(env, &dc->base, dc->pc); 4914af00be49SEmilio G. Cota dc->base.pc_next += 4; 4915878cc677SRichard Henderson 4916878cc677SRichard Henderson if (!decode(dc, insn)) { 4917ba9c09b4SRichard Henderson gen_exception(dc, TT_ILL_INSN); 4918878cc677SRichard Henderson } 4919fcf5ef2aSThomas Huth 4920af00be49SEmilio G. Cota if (dc->base.is_jmp == DISAS_NORETURN) { 49216e61bc94SEmilio G. Cota return; 4922c5e6ccdfSEmilio G. Cota } 4923af00be49SEmilio G. Cota if (dc->pc != dc->base.pc_next) { 49246e61bc94SEmilio G. Cota dc->base.is_jmp = DISAS_TOO_MANY; 4925af00be49SEmilio G. Cota } 49266e61bc94SEmilio G. Cota } 4927fcf5ef2aSThomas Huth 49286e61bc94SEmilio G. Cota static void sparc_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 49296e61bc94SEmilio G. Cota { 49306e61bc94SEmilio G. Cota DisasContext *dc = container_of(dcbase, DisasContext, base); 4931186e7890SRichard Henderson DisasDelayException *e, *e_next; 4932633c4283SRichard Henderson bool may_lookup; 49336e61bc94SEmilio G. Cota 493489527e3aSRichard Henderson finishing_insn(dc); 493589527e3aSRichard Henderson 493646bb0137SMark Cave-Ayland switch (dc->base.is_jmp) { 493746bb0137SMark Cave-Ayland case DISAS_NEXT: 493846bb0137SMark Cave-Ayland case DISAS_TOO_MANY: 4939633c4283SRichard Henderson if (((dc->pc | dc->npc) & 3) == 0) { 4940fcf5ef2aSThomas Huth /* static PC and NPC: we can use direct chaining */ 4941fcf5ef2aSThomas Huth gen_goto_tb(dc, 0, dc->pc, dc->npc); 4942633c4283SRichard Henderson break; 4943fcf5ef2aSThomas Huth } 4944633c4283SRichard Henderson 4945930f1865SRichard Henderson may_lookup = true; 4946633c4283SRichard Henderson if (dc->pc & 3) { 4947633c4283SRichard Henderson switch (dc->pc) { 4948633c4283SRichard Henderson case DYNAMIC_PC_LOOKUP: 4949633c4283SRichard Henderson break; 4950633c4283SRichard Henderson case DYNAMIC_PC: 4951633c4283SRichard Henderson may_lookup = false; 4952633c4283SRichard Henderson break; 4953633c4283SRichard Henderson default: 4954633c4283SRichard Henderson g_assert_not_reached(); 4955633c4283SRichard Henderson } 4956633c4283SRichard Henderson } else { 4957633c4283SRichard Henderson tcg_gen_movi_tl(cpu_pc, dc->pc); 4958633c4283SRichard Henderson } 4959633c4283SRichard Henderson 4960930f1865SRichard Henderson if (dc->npc & 3) { 4961930f1865SRichard Henderson switch (dc->npc) { 4962930f1865SRichard Henderson case JUMP_PC: 4963930f1865SRichard Henderson gen_generic_branch(dc); 4964930f1865SRichard Henderson break; 4965930f1865SRichard Henderson case DYNAMIC_PC: 4966930f1865SRichard Henderson may_lookup = false; 4967930f1865SRichard Henderson break; 4968930f1865SRichard Henderson case DYNAMIC_PC_LOOKUP: 4969930f1865SRichard Henderson break; 4970930f1865SRichard Henderson default: 4971930f1865SRichard Henderson g_assert_not_reached(); 4972930f1865SRichard Henderson } 4973930f1865SRichard Henderson } else { 4974930f1865SRichard Henderson tcg_gen_movi_tl(cpu_npc, dc->npc); 4975930f1865SRichard Henderson } 4976633c4283SRichard Henderson if (may_lookup) { 4977633c4283SRichard Henderson tcg_gen_lookup_and_goto_ptr(); 4978633c4283SRichard Henderson } else { 497907ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 4980fcf5ef2aSThomas Huth } 498146bb0137SMark Cave-Ayland break; 498246bb0137SMark Cave-Ayland 498346bb0137SMark Cave-Ayland case DISAS_NORETURN: 498446bb0137SMark Cave-Ayland break; 498546bb0137SMark Cave-Ayland 498646bb0137SMark Cave-Ayland case DISAS_EXIT: 498746bb0137SMark Cave-Ayland /* Exit TB */ 498846bb0137SMark Cave-Ayland save_state(dc); 498946bb0137SMark Cave-Ayland tcg_gen_exit_tb(NULL, 0); 499046bb0137SMark Cave-Ayland break; 499146bb0137SMark Cave-Ayland 499246bb0137SMark Cave-Ayland default: 499346bb0137SMark Cave-Ayland g_assert_not_reached(); 4994fcf5ef2aSThomas Huth } 4995186e7890SRichard Henderson 4996186e7890SRichard Henderson for (e = dc->delay_excp_list; e ; e = e_next) { 4997186e7890SRichard Henderson gen_set_label(e->lab); 4998186e7890SRichard Henderson 4999186e7890SRichard Henderson tcg_gen_movi_tl(cpu_pc, e->pc); 5000186e7890SRichard Henderson if (e->npc % 4 == 0) { 5001186e7890SRichard Henderson tcg_gen_movi_tl(cpu_npc, e->npc); 5002186e7890SRichard Henderson } 5003186e7890SRichard Henderson gen_helper_raise_exception(tcg_env, e->excp); 5004186e7890SRichard Henderson 5005186e7890SRichard Henderson e_next = e->next; 5006186e7890SRichard Henderson g_free(e); 5007186e7890SRichard Henderson } 5008fcf5ef2aSThomas Huth } 50096e61bc94SEmilio G. Cota 50108eb806a7SRichard Henderson static void sparc_tr_disas_log(const DisasContextBase *dcbase, 50118eb806a7SRichard Henderson CPUState *cpu, FILE *logfile) 50126e61bc94SEmilio G. Cota { 50138eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); 50148eb806a7SRichard Henderson target_disas(logfile, cpu, dcbase->pc_first, dcbase->tb->size); 50156e61bc94SEmilio G. Cota } 50166e61bc94SEmilio G. Cota 50176e61bc94SEmilio G. Cota static const TranslatorOps sparc_tr_ops = { 50186e61bc94SEmilio G. Cota .init_disas_context = sparc_tr_init_disas_context, 50196e61bc94SEmilio G. Cota .tb_start = sparc_tr_tb_start, 50206e61bc94SEmilio G. Cota .insn_start = sparc_tr_insn_start, 50216e61bc94SEmilio G. Cota .translate_insn = sparc_tr_translate_insn, 50226e61bc94SEmilio G. Cota .tb_stop = sparc_tr_tb_stop, 50236e61bc94SEmilio G. Cota .disas_log = sparc_tr_disas_log, 50246e61bc94SEmilio G. Cota }; 50256e61bc94SEmilio G. Cota 5026597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, 502732f0c394SAnton Johansson vaddr pc, void *host_pc) 50286e61bc94SEmilio G. Cota { 50296e61bc94SEmilio G. Cota DisasContext dc = {}; 50306e61bc94SEmilio G. Cota 5031306c8721SRichard Henderson translator_loop(cs, tb, max_insns, pc, host_pc, &sparc_tr_ops, &dc.base); 5032fcf5ef2aSThomas Huth } 5033fcf5ef2aSThomas Huth 503455c3ceefSRichard Henderson void sparc_tcg_init(void) 5035fcf5ef2aSThomas Huth { 5036fcf5ef2aSThomas Huth static const char gregnames[32][4] = { 5037fcf5ef2aSThomas Huth "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", 5038fcf5ef2aSThomas Huth "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", 5039fcf5ef2aSThomas Huth "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", 5040fcf5ef2aSThomas Huth "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7", 5041fcf5ef2aSThomas Huth }; 5042fcf5ef2aSThomas Huth static const char fregnames[32][4] = { 5043fcf5ef2aSThomas Huth "f0", "f2", "f4", "f6", "f8", "f10", "f12", "f14", 5044fcf5ef2aSThomas Huth "f16", "f18", "f20", "f22", "f24", "f26", "f28", "f30", 5045fcf5ef2aSThomas Huth "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", 5046fcf5ef2aSThomas Huth "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", 5047fcf5ef2aSThomas Huth }; 5048fcf5ef2aSThomas Huth 5049d8c5b92fSRichard Henderson static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = { 5050d8c5b92fSRichard Henderson #ifdef TARGET_SPARC64 5051d8c5b92fSRichard Henderson { &cpu_fprs, offsetof(CPUSPARCState, fprs), "fprs" }, 5052d8c5b92fSRichard Henderson { &cpu_fcc[0], offsetof(CPUSPARCState, fcc[0]), "fcc0" }, 5053d8c5b92fSRichard Henderson { &cpu_fcc[1], offsetof(CPUSPARCState, fcc[1]), "fcc1" }, 5054d8c5b92fSRichard Henderson { &cpu_fcc[2], offsetof(CPUSPARCState, fcc[2]), "fcc2" }, 5055d8c5b92fSRichard Henderson { &cpu_fcc[3], offsetof(CPUSPARCState, fcc[3]), "fcc3" }, 5056d8c5b92fSRichard Henderson #else 5057d8c5b92fSRichard Henderson { &cpu_fcc[0], offsetof(CPUSPARCState, fcc[0]), "fcc" }, 5058d8c5b92fSRichard Henderson #endif 5059d8c5b92fSRichard Henderson }; 5060d8c5b92fSRichard Henderson 5061fcf5ef2aSThomas Huth static const struct { TCGv *ptr; int off; const char *name; } rtl[] = { 5062fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 5063fcf5ef2aSThomas Huth { &cpu_gsr, offsetof(CPUSPARCState, gsr), "gsr" }, 50642a1905c7SRichard Henderson { &cpu_xcc_Z, offsetof(CPUSPARCState, xcc_Z), "xcc_Z" }, 50652a1905c7SRichard Henderson { &cpu_xcc_C, offsetof(CPUSPARCState, xcc_C), "xcc_C" }, 5066fcf5ef2aSThomas Huth #endif 50672a1905c7SRichard Henderson { &cpu_cc_N, offsetof(CPUSPARCState, cc_N), "cc_N" }, 50682a1905c7SRichard Henderson { &cpu_cc_V, offsetof(CPUSPARCState, cc_V), "cc_V" }, 50692a1905c7SRichard Henderson { &cpu_icc_Z, offsetof(CPUSPARCState, icc_Z), "icc_Z" }, 50702a1905c7SRichard Henderson { &cpu_icc_C, offsetof(CPUSPARCState, icc_C), "icc_C" }, 5071fcf5ef2aSThomas Huth { &cpu_cond, offsetof(CPUSPARCState, cond), "cond" }, 5072fcf5ef2aSThomas Huth { &cpu_pc, offsetof(CPUSPARCState, pc), "pc" }, 5073fcf5ef2aSThomas Huth { &cpu_npc, offsetof(CPUSPARCState, npc), "npc" }, 5074fcf5ef2aSThomas Huth { &cpu_y, offsetof(CPUSPARCState, y), "y" }, 5075fcf5ef2aSThomas Huth { &cpu_tbr, offsetof(CPUSPARCState, tbr), "tbr" }, 5076fcf5ef2aSThomas Huth }; 5077fcf5ef2aSThomas Huth 5078fcf5ef2aSThomas Huth unsigned int i; 5079fcf5ef2aSThomas Huth 5080ad75a51eSRichard Henderson cpu_regwptr = tcg_global_mem_new_ptr(tcg_env, 5081fcf5ef2aSThomas Huth offsetof(CPUSPARCState, regwptr), 5082fcf5ef2aSThomas Huth "regwptr"); 5083fcf5ef2aSThomas Huth 5084d8c5b92fSRichard Henderson for (i = 0; i < ARRAY_SIZE(r32); ++i) { 5085d8c5b92fSRichard Henderson *r32[i].ptr = tcg_global_mem_new_i32(tcg_env, r32[i].off, r32[i].name); 5086d8c5b92fSRichard Henderson } 5087d8c5b92fSRichard Henderson 5088fcf5ef2aSThomas Huth for (i = 0; i < ARRAY_SIZE(rtl); ++i) { 5089ad75a51eSRichard Henderson *rtl[i].ptr = tcg_global_mem_new(tcg_env, rtl[i].off, rtl[i].name); 5090fcf5ef2aSThomas Huth } 5091fcf5ef2aSThomas Huth 5092f764718dSRichard Henderson cpu_regs[0] = NULL; 5093fcf5ef2aSThomas Huth for (i = 1; i < 8; ++i) { 5094ad75a51eSRichard Henderson cpu_regs[i] = tcg_global_mem_new(tcg_env, 5095fcf5ef2aSThomas Huth offsetof(CPUSPARCState, gregs[i]), 5096fcf5ef2aSThomas Huth gregnames[i]); 5097fcf5ef2aSThomas Huth } 5098fcf5ef2aSThomas Huth 5099fcf5ef2aSThomas Huth for (i = 8; i < 32; ++i) { 5100fcf5ef2aSThomas Huth cpu_regs[i] = tcg_global_mem_new(cpu_regwptr, 5101fcf5ef2aSThomas Huth (i - 8) * sizeof(target_ulong), 5102fcf5ef2aSThomas Huth gregnames[i]); 5103fcf5ef2aSThomas Huth } 5104fcf5ef2aSThomas Huth 5105fcf5ef2aSThomas Huth for (i = 0; i < TARGET_DPREGS; i++) { 5106ad75a51eSRichard Henderson cpu_fpr[i] = tcg_global_mem_new_i64(tcg_env, 5107fcf5ef2aSThomas Huth offsetof(CPUSPARCState, fpr[i]), 5108fcf5ef2aSThomas Huth fregnames[i]); 5109fcf5ef2aSThomas Huth } 5110fcf5ef2aSThomas Huth } 5111fcf5ef2aSThomas Huth 5112f36aaa53SRichard Henderson void sparc_restore_state_to_opc(CPUState *cs, 5113f36aaa53SRichard Henderson const TranslationBlock *tb, 5114f36aaa53SRichard Henderson const uint64_t *data) 5115fcf5ef2aSThomas Huth { 5116f36aaa53SRichard Henderson SPARCCPU *cpu = SPARC_CPU(cs); 5117f36aaa53SRichard Henderson CPUSPARCState *env = &cpu->env; 5118fcf5ef2aSThomas Huth target_ulong pc = data[0]; 5119fcf5ef2aSThomas Huth target_ulong npc = data[1]; 5120fcf5ef2aSThomas Huth 5121fcf5ef2aSThomas Huth env->pc = pc; 5122fcf5ef2aSThomas Huth if (npc == DYNAMIC_PC) { 5123fcf5ef2aSThomas Huth /* dynamic NPC: already stored */ 5124fcf5ef2aSThomas Huth } else if (npc & JUMP_PC) { 5125fcf5ef2aSThomas Huth /* jump PC: use 'cond' and the jump targets of the translation */ 5126fcf5ef2aSThomas Huth if (env->cond) { 5127fcf5ef2aSThomas Huth env->npc = npc & ~3; 5128fcf5ef2aSThomas Huth } else { 5129fcf5ef2aSThomas Huth env->npc = pc + 4; 5130fcf5ef2aSThomas Huth } 5131fcf5ef2aSThomas Huth } else { 5132fcf5ef2aSThomas Huth env->npc = npc; 5133fcf5ef2aSThomas Huth } 5134fcf5ef2aSThomas Huth } 5135