1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * Xilinx MicroBlaze emulation for qemu: main translation routines. 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2009 Edgar E. Iglesias. 5fcf5ef2aSThomas Huth * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 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 10fcf5ef2aSThomas Huth * version 2 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 #include "cpu.h" 23fcf5ef2aSThomas Huth #include "disas/disas.h" 24fcf5ef2aSThomas Huth #include "exec/exec-all.h" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 26fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 27fcf5ef2aSThomas Huth #include "microblaze-decode.h" 28fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h" 29fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 3077fc6f5eSLluís Vilanova #include "exec/translator.h" 3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 32fcf5ef2aSThomas Huth 33fcf5ef2aSThomas Huth #include "trace-tcg.h" 34fcf5ef2aSThomas Huth #include "exec/log.h" 35fcf5ef2aSThomas Huth 36fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 37fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 38fcf5ef2aSThomas Huth 3977fc6f5eSLluís Vilanova /* is_jmp field values */ 4077fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 4177fc6f5eSLluís Vilanova #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ 4277fc6f5eSLluís Vilanova 43cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 440f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 453e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 461074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 479b158558SRichard Henderson static TCGv_i32 cpu_imm; 489b158558SRichard Henderson static TCGv_i32 cpu_btaken; 490f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 509b158558SRichard Henderson static TCGv_i32 cpu_iflags; 519b158558SRichard Henderson static TCGv cpu_res_addr; 529b158558SRichard Henderson static TCGv_i32 cpu_res_val; 53fcf5ef2aSThomas Huth 54fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 55fcf5ef2aSThomas Huth 56fcf5ef2aSThomas Huth /* This is the state at translation time. */ 57fcf5ef2aSThomas Huth typedef struct DisasContext { 58d4705ae0SRichard Henderson DisasContextBase base; 59fcf5ef2aSThomas Huth MicroBlazeCPU *cpu; 60fcf5ef2aSThomas Huth 61683a247eSRichard Henderson /* TCG op of the current insn_start. */ 62683a247eSRichard Henderson TCGOp *insn_start; 63683a247eSRichard Henderson 6420800179SRichard Henderson TCGv_i32 r0; 6520800179SRichard Henderson bool r0_set; 6620800179SRichard Henderson 67fcf5ef2aSThomas Huth /* Decoder. */ 68fcf5ef2aSThomas Huth int type_b; 69fcf5ef2aSThomas Huth uint32_t ir; 70d7ecb757SRichard Henderson uint32_t ext_imm; 71fcf5ef2aSThomas Huth uint8_t opcode; 72fcf5ef2aSThomas Huth uint8_t rd, ra, rb; 73fcf5ef2aSThomas Huth uint16_t imm; 74fcf5ef2aSThomas Huth 75fcf5ef2aSThomas Huth unsigned int cpustate_changed; 76fcf5ef2aSThomas Huth unsigned int delayed_branch; 77683a247eSRichard Henderson unsigned int tb_flags; 78fcf5ef2aSThomas Huth unsigned int clear_imm; 79287b1defSRichard Henderson int mem_index; 80fcf5ef2aSThomas Huth 81fcf5ef2aSThomas Huth #define JMP_NOJMP 0 82fcf5ef2aSThomas Huth #define JMP_DIRECT 1 83fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2 84fcf5ef2aSThomas Huth #define JMP_INDIRECT 3 85fcf5ef2aSThomas Huth unsigned int jmp; 86fcf5ef2aSThomas Huth uint32_t jmp_pc; 87fcf5ef2aSThomas Huth 88fcf5ef2aSThomas Huth int abort_at_next_insn; 89fcf5ef2aSThomas Huth } DisasContext; 90fcf5ef2aSThomas Huth 9120800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 9220800179SRichard Henderson { 9320800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 9420800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 9520800179SRichard Henderson } 9620800179SRichard Henderson return x; 9720800179SRichard Henderson } 9820800179SRichard Henderson 9944d1432bSRichard Henderson /* Include the auto-generated decoder. */ 10044d1432bSRichard Henderson #include "decode-insns.c.inc" 10144d1432bSRichard Henderson 102683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc) 103fcf5ef2aSThomas Huth { 104fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 105683a247eSRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) { 106683a247eSRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK); 107fcf5ef2aSThomas Huth } 108fcf5ef2aSThomas Huth } 109fcf5ef2aSThomas Huth 110d8e59c4aSRichard Henderson static inline void sync_jmpstate(DisasContext *dc) 111d8e59c4aSRichard Henderson { 112d8e59c4aSRichard Henderson if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 113d8e59c4aSRichard Henderson if (dc->jmp == JMP_DIRECT) { 114d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 115d8e59c4aSRichard Henderson } 116d8e59c4aSRichard Henderson dc->jmp = JMP_INDIRECT; 117d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 118d8e59c4aSRichard Henderson } 119d8e59c4aSRichard Henderson } 120d8e59c4aSRichard Henderson 12141ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 122fcf5ef2aSThomas Huth { 123fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 124fcf5ef2aSThomas Huth 125fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 126fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 127d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 128fcf5ef2aSThomas Huth } 129fcf5ef2aSThomas Huth 13041ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 13141ba37c4SRichard Henderson { 13241ba37c4SRichard Henderson t_sync_flags(dc); 133d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 13441ba37c4SRichard Henderson gen_raise_exception(dc, index); 13541ba37c4SRichard Henderson } 13641ba37c4SRichard Henderson 13741ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 13841ba37c4SRichard Henderson { 13941ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 14041ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 14141ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 14241ba37c4SRichard Henderson 14341ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 14441ba37c4SRichard Henderson } 14541ba37c4SRichard Henderson 146fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 147fcf5ef2aSThomas Huth { 148fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 149d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 150fcf5ef2aSThomas Huth #else 151fcf5ef2aSThomas Huth return true; 152fcf5ef2aSThomas Huth #endif 153fcf5ef2aSThomas Huth } 154fcf5ef2aSThomas Huth 155fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 156fcf5ef2aSThomas Huth { 157d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1580b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1590b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1600b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1610b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1620b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 163fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1640f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 165d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 166fcf5ef2aSThomas Huth } else { 1670f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 16807ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 169fcf5ef2aSThomas Huth } 170d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 171fcf5ef2aSThomas Huth } 172fcf5ef2aSThomas Huth 173bdfc1e88SEdgar E. Iglesias /* 1749ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1759ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1769ba8cd45SEdgar E. Iglesias */ 1779ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1789ba8cd45SEdgar E. Iglesias { 1792c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE) 1805143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 18141ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1829ba8cd45SEdgar E. Iglesias } 1839ba8cd45SEdgar E. Iglesias return cond; 1849ba8cd45SEdgar E. Iglesias } 1859ba8cd45SEdgar E. Iglesias 1869ba8cd45SEdgar E. Iglesias /* 187bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 188bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 189bdfc1e88SEdgar E. Iglesias */ 190bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 191bdfc1e88SEdgar E. Iglesias { 192287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX; 193bdfc1e88SEdgar E. Iglesias 1942c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) { 19541ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 196bdfc1e88SEdgar E. Iglesias } 197bdfc1e88SEdgar E. Iglesias return cond_user; 198bdfc1e88SEdgar E. Iglesias } 199bdfc1e88SEdgar E. Iglesias 200d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc) 201fcf5ef2aSThomas Huth { 202d7ecb757SRichard Henderson tcg_debug_assert(dc->type_b); 20320800179SRichard Henderson return typeb_imm(dc, (int16_t)dc->imm); 204fcf5ef2aSThomas Huth } 205fcf5ef2aSThomas Huth 206cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) 207fcf5ef2aSThomas Huth { 208fcf5ef2aSThomas Huth if (dc->type_b) { 209d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc)); 2109b158558SRichard Henderson return &cpu_imm; 211d7ecb757SRichard Henderson } 212fcf5ef2aSThomas Huth return &cpu_R[dc->rb]; 213fcf5ef2aSThomas Huth } 214fcf5ef2aSThomas Huth 21520800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 216fcf5ef2aSThomas Huth { 21720800179SRichard Henderson if (likely(reg != 0)) { 21820800179SRichard Henderson return cpu_R[reg]; 219fcf5ef2aSThomas Huth } 22020800179SRichard Henderson if (!dc->r0_set) { 22120800179SRichard Henderson if (dc->r0 == NULL) { 22220800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 223fcf5ef2aSThomas Huth } 22420800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 22520800179SRichard Henderson dc->r0_set = true; 22620800179SRichard Henderson } 22720800179SRichard Henderson return dc->r0; 228fcf5ef2aSThomas Huth } 229fcf5ef2aSThomas Huth 23020800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 23120800179SRichard Henderson { 23220800179SRichard Henderson if (likely(reg != 0)) { 23320800179SRichard Henderson return cpu_R[reg]; 23420800179SRichard Henderson } 23520800179SRichard Henderson if (dc->r0 == NULL) { 23620800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 23720800179SRichard Henderson } 23820800179SRichard Henderson return dc->r0; 239fcf5ef2aSThomas Huth } 240fcf5ef2aSThomas Huth 24120800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 24220800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 24320800179SRichard Henderson { 24420800179SRichard Henderson TCGv_i32 rd, ra, rb; 24520800179SRichard Henderson 24620800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 24720800179SRichard Henderson return true; 248fcf5ef2aSThomas Huth } 24920800179SRichard Henderson 25020800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 25120800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 25220800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 25320800179SRichard Henderson fn(rd, ra, rb); 25420800179SRichard Henderson return true; 25520800179SRichard Henderson } 25620800179SRichard Henderson 25739cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, 25839cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32)) 25939cf3864SRichard Henderson { 26039cf3864SRichard Henderson TCGv_i32 rd, ra; 26139cf3864SRichard Henderson 26239cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) { 26339cf3864SRichard Henderson return true; 26439cf3864SRichard Henderson } 26539cf3864SRichard Henderson 26639cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd); 26739cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra); 26839cf3864SRichard Henderson fn(rd, ra); 26939cf3864SRichard Henderson return true; 27039cf3864SRichard Henderson } 27139cf3864SRichard Henderson 27220800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 27320800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 27420800179SRichard Henderson { 27520800179SRichard Henderson TCGv_i32 rd, ra; 27620800179SRichard Henderson 27720800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 27820800179SRichard Henderson return true; 27920800179SRichard Henderson } 28020800179SRichard Henderson 28120800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 28220800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 28320800179SRichard Henderson fni(rd, ra, arg->imm); 28420800179SRichard Henderson return true; 28520800179SRichard Henderson } 28620800179SRichard Henderson 28720800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 28820800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 28920800179SRichard Henderson { 29020800179SRichard Henderson TCGv_i32 rd, ra, imm; 29120800179SRichard Henderson 29220800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 29320800179SRichard Henderson return true; 29420800179SRichard Henderson } 29520800179SRichard Henderson 29620800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 29720800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 29820800179SRichard Henderson imm = tcg_const_i32(arg->imm); 29920800179SRichard Henderson 30020800179SRichard Henderson fn(rd, ra, imm); 30120800179SRichard Henderson 30220800179SRichard Henderson tcg_temp_free_i32(imm); 30320800179SRichard Henderson return true; 30420800179SRichard Henderson } 30520800179SRichard Henderson 30620800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 30720800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 30820800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 30920800179SRichard Henderson 310607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 311607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 312607f5767SRichard Henderson { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } 313607f5767SRichard Henderson 31439cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 31539cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 31639cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 31739cf3864SRichard Henderson 31839cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 31939cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 32039cf3864SRichard Henderson { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); } 32139cf3864SRichard Henderson 32220800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 32320800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 32420800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 32520800179SRichard Henderson 32697955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 32797955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 32897955cebSRichard Henderson { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } 32997955cebSRichard Henderson 33020800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 33120800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 33220800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 33320800179SRichard Henderson 334d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 335d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 336d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 337d5aead3dSRichard Henderson 338d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 339d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 340d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 341d5aead3dSRichard Henderson 34220800179SRichard Henderson /* No input carry, but output carry. */ 34320800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 34420800179SRichard Henderson { 34520800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 34620800179SRichard Henderson 34720800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 34820800179SRichard Henderson 34920800179SRichard Henderson tcg_temp_free_i32(zero); 35020800179SRichard Henderson } 35120800179SRichard Henderson 35220800179SRichard Henderson /* Input and output carry. */ 35320800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 35420800179SRichard Henderson { 35520800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 35620800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 35720800179SRichard Henderson 35820800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 35920800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 36020800179SRichard Henderson 36120800179SRichard Henderson tcg_temp_free_i32(tmp); 36220800179SRichard Henderson tcg_temp_free_i32(zero); 36320800179SRichard Henderson } 36420800179SRichard Henderson 36520800179SRichard Henderson /* Input carry, but no output carry. */ 36620800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 36720800179SRichard Henderson { 36820800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 36920800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 37020800179SRichard Henderson } 37120800179SRichard Henderson 37220800179SRichard Henderson DO_TYPEA(add, true, gen_add) 37320800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 37420800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 37520800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 37620800179SRichard Henderson 37720800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 37820800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 37920800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 38020800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 38120800179SRichard Henderson 382cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 383cb0a0a4cSRichard Henderson { 384cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 385cb0a0a4cSRichard Henderson } 386cb0a0a4cSRichard Henderson 387cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 388cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 389cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 390cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 391cb0a0a4cSRichard Henderson 392081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 393081d8e02SRichard Henderson { 394081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 395081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 396081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 397081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 398081d8e02SRichard Henderson } 399081d8e02SRichard Henderson 400081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 401081d8e02SRichard Henderson { 402081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 403081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 404081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 405081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 406081d8e02SRichard Henderson } 407081d8e02SRichard Henderson 408081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 409081d8e02SRichard Henderson { 410081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 411081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 412081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 413081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 414081d8e02SRichard Henderson } 415081d8e02SRichard Henderson 416081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 417081d8e02SRichard Henderson { 418081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 419081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 420081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 421081d8e02SRichard Henderson 422081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 423081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 424081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 425081d8e02SRichard Henderson imm_w, imm_s); 426081d8e02SRichard Henderson } else { 427081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 428081d8e02SRichard Henderson } 429081d8e02SRichard Henderson } 430081d8e02SRichard Henderson 431081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 432081d8e02SRichard Henderson { 433081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 434081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 435081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 436081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 437081d8e02SRichard Henderson 438081d8e02SRichard Henderson if (imm_w < imm_s) { 439081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 440081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 441081d8e02SRichard Henderson imm_w, imm_s); 442081d8e02SRichard Henderson } else { 443081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 444081d8e02SRichard Henderson } 445081d8e02SRichard Henderson } 446081d8e02SRichard Henderson 447081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 448081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 449081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 450081d8e02SRichard Henderson 451081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 452081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 453081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 454081d8e02SRichard Henderson 455081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 456081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 457081d8e02SRichard Henderson 45839cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 45939cf3864SRichard Henderson { 46039cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 46139cf3864SRichard Henderson } 46239cf3864SRichard Henderson 46339cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 46439cf3864SRichard Henderson 46558b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 46658b48b63SRichard Henderson { 46758b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 46858b48b63SRichard Henderson 46958b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 47058b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 47158b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 47258b48b63SRichard Henderson tcg_temp_free_i32(lt); 47358b48b63SRichard Henderson } 47458b48b63SRichard Henderson 47558b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 47658b48b63SRichard Henderson { 47758b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 47858b48b63SRichard Henderson 47958b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 48058b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 48158b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 48258b48b63SRichard Henderson tcg_temp_free_i32(lt); 48358b48b63SRichard Henderson } 48458b48b63SRichard Henderson 48558b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 48658b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 487a2b0b90eSRichard Henderson 488d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 489d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 490d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 491d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 492d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 493d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 494d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 495d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 496d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 497d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 498d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 499d5aead3dSRichard Henderson 500d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 501d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 502d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 503d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 504d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 505d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 506d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 507d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 508d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 509d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 510d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 511d5aead3dSRichard Henderson 512d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 513d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 514d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 515d5aead3dSRichard Henderson 516d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 517d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 518d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 519d5aead3dSRichard Henderson 520d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 521b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 522b1354342SRichard Henderson { 523b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 524b1354342SRichard Henderson } 525b1354342SRichard Henderson 526b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 527b1354342SRichard Henderson { 528b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 529b1354342SRichard Henderson } 530b1354342SRichard Henderson 531b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 532b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 533b1354342SRichard Henderson 534e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 535e64b2e5cSRichard Henderson { 536e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 537e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 538e64b2e5cSRichard Henderson dc->tb_flags |= IMM_FLAG; 539e64b2e5cSRichard Henderson dc->clear_imm = 0; 540e64b2e5cSRichard Henderson return true; 541e64b2e5cSRichard Henderson } 542e64b2e5cSRichard Henderson 54397955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 54497955cebSRichard Henderson { 54597955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 54697955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 54797955cebSRichard Henderson tcg_temp_free_i32(tmp); 54897955cebSRichard Henderson } 54997955cebSRichard Henderson 55097955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 55197955cebSRichard Henderson { 55297955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 55397955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 55497955cebSRichard Henderson tcg_temp_free_i32(tmp); 55597955cebSRichard Henderson } 55697955cebSRichard Henderson 55797955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 55897955cebSRichard Henderson { 55997955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 56097955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 56197955cebSRichard Henderson tcg_temp_free_i32(tmp); 56297955cebSRichard Henderson } 56397955cebSRichard Henderson 56497955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 56597955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 56697955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 56797955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 56897955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 56997955cebSRichard Henderson 570cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 571cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 572cb0a0a4cSRichard Henderson 573607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 574607f5767SRichard Henderson { 575607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 576607f5767SRichard Henderson } 577607f5767SRichard Henderson 578607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 579607f5767SRichard Henderson { 580607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 581607f5767SRichard Henderson } 582607f5767SRichard Henderson 583607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 584607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 585607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 586607f5767SRichard Henderson 587a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 588a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 589a2b0b90eSRichard Henderson { 590a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 591a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 592a2b0b90eSRichard Henderson } 593a2b0b90eSRichard Henderson 594a2b0b90eSRichard Henderson /* Input and output carry. */ 595a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 596a2b0b90eSRichard Henderson { 597a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 598a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 599a2b0b90eSRichard Henderson 600a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 601a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 602a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 603a2b0b90eSRichard Henderson 604a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 605a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 606a2b0b90eSRichard Henderson } 607a2b0b90eSRichard Henderson 608a2b0b90eSRichard Henderson /* No input or output carry. */ 609a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 610a2b0b90eSRichard Henderson { 611a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 612a2b0b90eSRichard Henderson } 613a2b0b90eSRichard Henderson 614a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 615a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 616a2b0b90eSRichard Henderson { 617a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 618a2b0b90eSRichard Henderson 619a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 620a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 621a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 622a2b0b90eSRichard Henderson 623a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 624a2b0b90eSRichard Henderson } 625a2b0b90eSRichard Henderson 626a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 627a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 628a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 629a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 630a2b0b90eSRichard Henderson 631a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 632a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 633a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 634a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 635a2b0b90eSRichard Henderson 63639cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 63739cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 63839cf3864SRichard Henderson 63939cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 64039cf3864SRichard Henderson { 64139cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 64239cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 64339cf3864SRichard Henderson } 64439cf3864SRichard Henderson 64539cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 64639cf3864SRichard Henderson { 64739cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 64839cf3864SRichard Henderson 64939cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 65039cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 65139cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 65239cf3864SRichard Henderson 65339cf3864SRichard Henderson tcg_temp_free_i32(tmp); 65439cf3864SRichard Henderson } 65539cf3864SRichard Henderson 65639cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 65739cf3864SRichard Henderson { 65839cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 65939cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 66039cf3864SRichard Henderson } 66139cf3864SRichard Henderson 66239cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 66339cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 66439cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 66539cf3864SRichard Henderson 66639cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 66739cf3864SRichard Henderson { 66839cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 66939cf3864SRichard Henderson } 67039cf3864SRichard Henderson 67139cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 67239cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 67339cf3864SRichard Henderson 67439cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 67539cf3864SRichard Henderson { 67639cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 67739cf3864SRichard Henderson trap_userspace(dc, true); 67839cf3864SRichard Henderson return true; 67939cf3864SRichard Henderson } 68039cf3864SRichard Henderson 681cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 682cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 683cb0a0a4cSRichard Henderson 684d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 685d8e59c4aSRichard Henderson { 686d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 687d8e59c4aSRichard Henderson 688d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 689d8e59c4aSRichard Henderson if (ra && rb) { 690d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 691d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 692d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 693d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 694d8e59c4aSRichard Henderson } else if (ra) { 695d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 696d8e59c4aSRichard Henderson } else if (rb) { 697d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 698d8e59c4aSRichard Henderson } else { 699d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 700d8e59c4aSRichard Henderson } 701d8e59c4aSRichard Henderson 702d8e59c4aSRichard Henderson if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) { 703d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 704d8e59c4aSRichard Henderson } 705d8e59c4aSRichard Henderson return ret; 706d8e59c4aSRichard Henderson } 707d8e59c4aSRichard Henderson 708d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 709d8e59c4aSRichard Henderson { 710d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 711d8e59c4aSRichard Henderson 712d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 713d8e59c4aSRichard Henderson if (ra) { 714d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 715d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 716d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 717d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 718d8e59c4aSRichard Henderson } else { 719d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 720d8e59c4aSRichard Henderson } 721d8e59c4aSRichard Henderson 722d8e59c4aSRichard Henderson if (ra == 1 && dc->cpu->cfg.stackprot) { 723d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 724d8e59c4aSRichard Henderson } 725d8e59c4aSRichard Henderson return ret; 726d8e59c4aSRichard Henderson } 727d8e59c4aSRichard Henderson 728d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 729d8e59c4aSRichard Henderson { 730d8e59c4aSRichard Henderson int addr_size = dc->cpu->cfg.addr_size; 731d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 732d8e59c4aSRichard Henderson 733d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 734d8e59c4aSRichard Henderson if (rb) { 735d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 736d8e59c4aSRichard Henderson } else { 737d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 738d8e59c4aSRichard Henderson } 739d8e59c4aSRichard Henderson } else { 740d8e59c4aSRichard Henderson if (rb) { 741d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 742d8e59c4aSRichard Henderson } else { 743d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 744d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 745d8e59c4aSRichard Henderson } 746d8e59c4aSRichard Henderson if (addr_size < 64) { 747d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 748d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 749d8e59c4aSRichard Henderson } 750d8e59c4aSRichard Henderson } 751d8e59c4aSRichard Henderson return ret; 752d8e59c4aSRichard Henderson } 753d8e59c4aSRichard Henderson 754*ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd, 755*ab0c8d0fSRichard Henderson MemOp size, bool store) 756*ab0c8d0fSRichard Henderson { 757*ab0c8d0fSRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); 758*ab0c8d0fSRichard Henderson 759*ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG; 760*ab0c8d0fSRichard Henderson iflags |= rd << 5; 761*ab0c8d0fSRichard Henderson iflags |= store * ESR_S; 762*ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W; 763*ab0c8d0fSRichard Henderson 764*ab0c8d0fSRichard Henderson tcg_set_insn_start_param(dc->insn_start, 1, iflags); 765*ab0c8d0fSRichard Henderson } 766*ab0c8d0fSRichard Henderson 767d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 768d8e59c4aSRichard Henderson int mem_index, bool rev) 769d8e59c4aSRichard Henderson { 770d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 771d8e59c4aSRichard Henderson 772d8e59c4aSRichard Henderson /* 773d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 774d8e59c4aSRichard Henderson * 775d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 776d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 777d8e59c4aSRichard Henderson */ 778d8e59c4aSRichard Henderson if (rev) { 779d8e59c4aSRichard Henderson if (size > MO_8) { 780d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 781d8e59c4aSRichard Henderson } 782d8e59c4aSRichard Henderson if (size < MO_32) { 783d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 784d8e59c4aSRichard Henderson } 785d8e59c4aSRichard Henderson } 786d8e59c4aSRichard Henderson 787d8e59c4aSRichard Henderson sync_jmpstate(dc); 788d8e59c4aSRichard Henderson 789*ab0c8d0fSRichard Henderson if (size > MO_8 && 790*ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 791*ab0c8d0fSRichard Henderson dc->cpu->cfg.unaligned_exceptions) { 792*ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false); 793*ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 794d8e59c4aSRichard Henderson } 795d8e59c4aSRichard Henderson 796*ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); 797d8e59c4aSRichard Henderson 798d8e59c4aSRichard Henderson tcg_temp_free(addr); 799d8e59c4aSRichard Henderson return true; 800d8e59c4aSRichard Henderson } 801d8e59c4aSRichard Henderson 802d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 803d8e59c4aSRichard Henderson { 804d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 805d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 806d8e59c4aSRichard Henderson } 807d8e59c4aSRichard Henderson 808d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 809d8e59c4aSRichard Henderson { 810d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 811d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 812d8e59c4aSRichard Henderson } 813d8e59c4aSRichard Henderson 814d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 815d8e59c4aSRichard Henderson { 816d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 817d8e59c4aSRichard Henderson return true; 818d8e59c4aSRichard Henderson } 819d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 820d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 821d8e59c4aSRichard Henderson } 822d8e59c4aSRichard Henderson 823d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 824d8e59c4aSRichard Henderson { 825d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 826d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 827d8e59c4aSRichard Henderson } 828d8e59c4aSRichard Henderson 829d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 830d8e59c4aSRichard Henderson { 831d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 832d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 833d8e59c4aSRichard Henderson } 834d8e59c4aSRichard Henderson 835d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 836d8e59c4aSRichard Henderson { 837d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 838d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 839d8e59c4aSRichard Henderson } 840d8e59c4aSRichard Henderson 841d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 842d8e59c4aSRichard Henderson { 843d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 844d8e59c4aSRichard Henderson return true; 845d8e59c4aSRichard Henderson } 846d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 847d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 848d8e59c4aSRichard Henderson } 849d8e59c4aSRichard Henderson 850d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 851d8e59c4aSRichard Henderson { 852d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 853d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 854d8e59c4aSRichard Henderson } 855d8e59c4aSRichard Henderson 856d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 857d8e59c4aSRichard Henderson { 858d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 859d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 860d8e59c4aSRichard Henderson } 861d8e59c4aSRichard Henderson 862d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 863d8e59c4aSRichard Henderson { 864d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 865d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 866d8e59c4aSRichard Henderson } 867d8e59c4aSRichard Henderson 868d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 869d8e59c4aSRichard Henderson { 870d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 871d8e59c4aSRichard Henderson return true; 872d8e59c4aSRichard Henderson } 873d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 874d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 875d8e59c4aSRichard Henderson } 876d8e59c4aSRichard Henderson 877d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg) 878d8e59c4aSRichard Henderson { 879d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 880d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 881d8e59c4aSRichard Henderson } 882d8e59c4aSRichard Henderson 883d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg) 884d8e59c4aSRichard Henderson { 885d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 886d8e59c4aSRichard Henderson 887d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */ 888d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 889d8e59c4aSRichard Henderson 890d8e59c4aSRichard Henderson sync_jmpstate(dc); 891d8e59c4aSRichard Henderson 892d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); 893d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 894d8e59c4aSRichard Henderson tcg_temp_free(addr); 895d8e59c4aSRichard Henderson 896d8e59c4aSRichard Henderson if (arg->rd) { 897d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 898d8e59c4aSRichard Henderson } 899d8e59c4aSRichard Henderson 900d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 901d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 902d8e59c4aSRichard Henderson return true; 903d8e59c4aSRichard Henderson } 904d8e59c4aSRichard Henderson 905d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 906d8e59c4aSRichard Henderson int mem_index, bool rev) 907d8e59c4aSRichard Henderson { 908d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 909d8e59c4aSRichard Henderson 910d8e59c4aSRichard Henderson /* 911d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 912d8e59c4aSRichard Henderson * 913d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 914d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 915d8e59c4aSRichard Henderson */ 916d8e59c4aSRichard Henderson if (rev) { 917d8e59c4aSRichard Henderson if (size > MO_8) { 918d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 919d8e59c4aSRichard Henderson } 920d8e59c4aSRichard Henderson if (size < MO_32) { 921d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 922d8e59c4aSRichard Henderson } 923d8e59c4aSRichard Henderson } 924d8e59c4aSRichard Henderson 925d8e59c4aSRichard Henderson sync_jmpstate(dc); 926d8e59c4aSRichard Henderson 927*ab0c8d0fSRichard Henderson if (size > MO_8 && 928*ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 929*ab0c8d0fSRichard Henderson dc->cpu->cfg.unaligned_exceptions) { 930*ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true); 931*ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 932d8e59c4aSRichard Henderson } 933d8e59c4aSRichard Henderson 934*ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 935*ab0c8d0fSRichard Henderson 936d8e59c4aSRichard Henderson tcg_temp_free(addr); 937d8e59c4aSRichard Henderson return true; 938d8e59c4aSRichard Henderson } 939d8e59c4aSRichard Henderson 940d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 941d8e59c4aSRichard Henderson { 942d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 943d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 944d8e59c4aSRichard Henderson } 945d8e59c4aSRichard Henderson 946d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 947d8e59c4aSRichard Henderson { 948d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 949d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 950d8e59c4aSRichard Henderson } 951d8e59c4aSRichard Henderson 952d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 953d8e59c4aSRichard Henderson { 954d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 955d8e59c4aSRichard Henderson return true; 956d8e59c4aSRichard Henderson } 957d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 958d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 959d8e59c4aSRichard Henderson } 960d8e59c4aSRichard Henderson 961d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 962d8e59c4aSRichard Henderson { 963d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 964d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 965d8e59c4aSRichard Henderson } 966d8e59c4aSRichard Henderson 967d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg) 968d8e59c4aSRichard Henderson { 969d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 970d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 971d8e59c4aSRichard Henderson } 972d8e59c4aSRichard Henderson 973d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 974d8e59c4aSRichard Henderson { 975d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 976d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 977d8e59c4aSRichard Henderson } 978d8e59c4aSRichard Henderson 979d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 980d8e59c4aSRichard Henderson { 981d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 982d8e59c4aSRichard Henderson return true; 983d8e59c4aSRichard Henderson } 984d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 985d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 986d8e59c4aSRichard Henderson } 987d8e59c4aSRichard Henderson 988d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 989d8e59c4aSRichard Henderson { 990d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 991d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 992d8e59c4aSRichard Henderson } 993d8e59c4aSRichard Henderson 994d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 995d8e59c4aSRichard Henderson { 996d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 997d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 998d8e59c4aSRichard Henderson } 999d8e59c4aSRichard Henderson 1000d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 1001d8e59c4aSRichard Henderson { 1002d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1003d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 1004d8e59c4aSRichard Henderson } 1005d8e59c4aSRichard Henderson 1006d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 1007d8e59c4aSRichard Henderson { 1008d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 1009d8e59c4aSRichard Henderson return true; 1010d8e59c4aSRichard Henderson } 1011d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 1012d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 1013d8e59c4aSRichard Henderson } 1014d8e59c4aSRichard Henderson 1015d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 1016d8e59c4aSRichard Henderson { 1017d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 1018d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 1019d8e59c4aSRichard Henderson } 1020d8e59c4aSRichard Henderson 1021d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 1022d8e59c4aSRichard Henderson { 1023d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1024d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 1025d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 1026d8e59c4aSRichard Henderson TCGv_i32 tval; 1027d8e59c4aSRichard Henderson 1028d8e59c4aSRichard Henderson sync_jmpstate(dc); 1029d8e59c4aSRichard Henderson 1030d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 1031d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1032d8e59c4aSRichard Henderson 1033d8e59c4aSRichard Henderson /* 1034d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 1035d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 1036d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 1037d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 1038d8e59c4aSRichard Henderson */ 1039d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 1040d8e59c4aSRichard Henderson tcg_temp_free(addr); 1041d8e59c4aSRichard Henderson 1042d8e59c4aSRichard Henderson /* 1043d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 1044d8e59c4aSRichard Henderson * the reserved location. 1045d8e59c4aSRichard Henderson */ 1046d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1047d8e59c4aSRichard Henderson 1048d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1049d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1050d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1051d8e59c4aSRichard Henderson 1052d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1053d8e59c4aSRichard Henderson tcg_temp_free_i32(tval); 1054d8e59c4aSRichard Henderson 1055d8e59c4aSRichard Henderson /* Success */ 1056d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1057d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1058d8e59c4aSRichard Henderson 1059d8e59c4aSRichard Henderson /* Failure */ 1060d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1061d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1062d8e59c4aSRichard Henderson 1063d8e59c4aSRichard Henderson gen_set_label(swx_done); 1064d8e59c4aSRichard Henderson 1065d8e59c4aSRichard Henderson /* 1066d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1067d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1068d8e59c4aSRichard Henderson */ 1069d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1070d8e59c4aSRichard Henderson return true; 1071d8e59c4aSRichard Henderson } 1072d8e59c4aSRichard Henderson 107320800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 107420800179SRichard Henderson { 107520800179SRichard Henderson /* If opcode_0_illegal, trap. */ 107620800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 107720800179SRichard Henderson trap_illegal(dc, true); 107820800179SRichard Henderson return true; 107920800179SRichard Henderson } 108020800179SRichard Henderson /* 108120800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 108220800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 108320800179SRichard Henderson */ 108420800179SRichard Henderson return false; 1085fcf5ef2aSThomas Huth } 1086fcf5ef2aSThomas Huth 10871074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 1088fcf5ef2aSThomas Huth { 10891074c0fbSRichard Henderson TCGv_i32 t; 10901074c0fbSRichard Henderson 10911074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 10921074c0fbSRichard Henderson t = tcg_temp_new_i32(); 10931074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 10941074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 10951074c0fbSRichard Henderson tcg_temp_free_i32(t); 1096fcf5ef2aSThomas Huth } 1097fcf5ef2aSThomas Huth 10981074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 1099fcf5ef2aSThomas Huth { 1100fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 11011074c0fbSRichard Henderson 11021074c0fbSRichard Henderson /* Install MSR_C. */ 11031074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 11041074c0fbSRichard Henderson 11051074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 11061074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 1107fcf5ef2aSThomas Huth } 1108fcf5ef2aSThomas Huth 1109fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc) 1110fcf5ef2aSThomas Huth { 1111fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 1112cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 11132023e9a3SEdgar E. Iglesias unsigned int sr, rn; 1114f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 1115fcf5ef2aSThomas Huth 11162023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 11172023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 11182023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 1119fcf5ef2aSThomas Huth dc->type_b = 1; 11202023e9a3SEdgar E. Iglesias if (to) { 1121fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 1122f0f7e7f7SEdgar E. Iglesias } 1123f0f7e7f7SEdgar E. Iglesias 1124f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 1125f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 1126f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 1127f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 1128f0f7e7f7SEdgar E. Iglesias 1129f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 11302023e9a3SEdgar E. Iglesias } 1131fcf5ef2aSThomas Huth 1132fcf5ef2aSThomas Huth /* msrclr and msrset. */ 11332023e9a3SEdgar E. Iglesias if (clrset) { 11342023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 1135fcf5ef2aSThomas Huth 113656837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 1137fcf5ef2aSThomas Huth /* nop??? */ 1138fcf5ef2aSThomas Huth return; 1139fcf5ef2aSThomas Huth } 1140fcf5ef2aSThomas Huth 1141bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 1142fcf5ef2aSThomas Huth return; 1143fcf5ef2aSThomas Huth } 1144fcf5ef2aSThomas Huth 1145fcf5ef2aSThomas Huth if (dc->rd) 1146fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 1147fcf5ef2aSThomas Huth 1148cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1149cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1150fcf5ef2aSThomas Huth msr_read(dc, t0); 1151cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 1152fcf5ef2aSThomas Huth 1153fcf5ef2aSThomas Huth if (clr) { 1154cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 1155cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 1156fcf5ef2aSThomas Huth } else 1157cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 1158fcf5ef2aSThomas Huth msr_write(dc, t0); 1159cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1160cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1161d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1162d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1163fcf5ef2aSThomas Huth return; 1164fcf5ef2aSThomas Huth } 1165fcf5ef2aSThomas Huth 1166bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 1167fcf5ef2aSThomas Huth return; 1168fcf5ef2aSThomas Huth } 1169fcf5ef2aSThomas Huth 1170fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 1171fcf5ef2aSThomas Huth /* Catch read/writes to the mmu block. */ 1172fcf5ef2aSThomas Huth if ((sr & ~0xff) == 0x1000) { 1173f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 117405a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 117505a9a651SEdgar E. Iglesias 1176fcf5ef2aSThomas Huth sr &= 7; 117705a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 117805a9a651SEdgar E. Iglesias if (to) { 1179f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 118005a9a651SEdgar E. Iglesias } else { 1181f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 118205a9a651SEdgar E. Iglesias } 118305a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 1184f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 1185fcf5ef2aSThomas Huth return; 1186fcf5ef2aSThomas Huth } 1187fcf5ef2aSThomas Huth #endif 1188fcf5ef2aSThomas Huth 1189fcf5ef2aSThomas Huth if (to) { 1190fcf5ef2aSThomas Huth switch (sr) { 1191aa28e6d4SRichard Henderson case SR_PC: 1192fcf5ef2aSThomas Huth break; 1193aa28e6d4SRichard Henderson case SR_MSR: 1194fcf5ef2aSThomas Huth msr_write(dc, cpu_R[dc->ra]); 1195fcf5ef2aSThomas Huth break; 1196351527b7SEdgar E. Iglesias case SR_EAR: 1197dbdb77c4SRichard Henderson { 1198dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1199dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 1200dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 1201dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1202dbdb77c4SRichard Henderson } 1203aa28e6d4SRichard Henderson break; 1204351527b7SEdgar E. Iglesias case SR_ESR: 120541ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 120641ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 1207aa28e6d4SRichard Henderson break; 1208ab6dd380SEdgar E. Iglesias case SR_FSR: 120986017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 121086017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 1211aa28e6d4SRichard Henderson break; 1212aa28e6d4SRichard Henderson case SR_BTR: 1213ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 1214ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 1215aa28e6d4SRichard Henderson break; 1216aa28e6d4SRichard Henderson case SR_EDR: 121739db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 121839db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 1219fcf5ef2aSThomas Huth break; 1220fcf5ef2aSThomas Huth case 0x800: 1221cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 1222cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 1223fcf5ef2aSThomas Huth break; 1224fcf5ef2aSThomas Huth case 0x802: 1225cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 1226cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 1227fcf5ef2aSThomas Huth break; 1228fcf5ef2aSThomas Huth default: 1229fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 1230fcf5ef2aSThomas Huth break; 1231fcf5ef2aSThomas Huth } 1232fcf5ef2aSThomas Huth } else { 1233fcf5ef2aSThomas Huth switch (sr) { 1234aa28e6d4SRichard Henderson case SR_PC: 1235d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1236fcf5ef2aSThomas Huth break; 1237aa28e6d4SRichard Henderson case SR_MSR: 1238fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 1239fcf5ef2aSThomas Huth break; 1240351527b7SEdgar E. Iglesias case SR_EAR: 1241dbdb77c4SRichard Henderson { 1242dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1243dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 1244a1b48e3aSEdgar E. Iglesias if (extended) { 1245dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 1246aa28e6d4SRichard Henderson } else { 1247dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 1248dbdb77c4SRichard Henderson } 1249dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1250a1b48e3aSEdgar E. Iglesias } 1251aa28e6d4SRichard Henderson break; 1252351527b7SEdgar E. Iglesias case SR_ESR: 125341ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 125441ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 1255aa28e6d4SRichard Henderson break; 1256351527b7SEdgar E. Iglesias case SR_FSR: 125786017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 125886017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 1259aa28e6d4SRichard Henderson break; 1260351527b7SEdgar E. Iglesias case SR_BTR: 1261ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 1262ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 1263aa28e6d4SRichard Henderson break; 12647cdae31dSTong Ho case SR_EDR: 126539db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 126639db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 1267fcf5ef2aSThomas Huth break; 1268fcf5ef2aSThomas Huth case 0x800: 1269cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 1270cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 1271fcf5ef2aSThomas Huth break; 1272fcf5ef2aSThomas Huth case 0x802: 1273cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 1274cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 1275fcf5ef2aSThomas Huth break; 1276351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 1277fcf5ef2aSThomas Huth rn = sr & 0xf; 1278cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 1279fcf5ef2aSThomas Huth cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 1280fcf5ef2aSThomas Huth break; 1281fcf5ef2aSThomas Huth default: 1282fcf5ef2aSThomas Huth cpu_abort(cs, "unknown mfs reg %x\n", sr); 1283fcf5ef2aSThomas Huth break; 1284fcf5ef2aSThomas Huth } 1285fcf5ef2aSThomas Huth } 1286fcf5ef2aSThomas Huth 1287fcf5ef2aSThomas Huth if (dc->rd == 0) { 1288cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 1289fcf5ef2aSThomas Huth } 1290fcf5ef2aSThomas Huth } 1291fcf5ef2aSThomas Huth 1292fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc, 12939e6e1828SEdgar E. Iglesias TCGv_i32 d, TCGv_i32 a) 1294fcf5ef2aSThomas Huth { 1295d89b86e9SEdgar E. Iglesias static const int mb_to_tcg_cc[] = { 1296d89b86e9SEdgar E. Iglesias [CC_EQ] = TCG_COND_EQ, 1297d89b86e9SEdgar E. Iglesias [CC_NE] = TCG_COND_NE, 1298d89b86e9SEdgar E. Iglesias [CC_LT] = TCG_COND_LT, 1299d89b86e9SEdgar E. Iglesias [CC_LE] = TCG_COND_LE, 1300d89b86e9SEdgar E. Iglesias [CC_GE] = TCG_COND_GE, 1301d89b86e9SEdgar E. Iglesias [CC_GT] = TCG_COND_GT, 1302d89b86e9SEdgar E. Iglesias }; 1303d89b86e9SEdgar E. Iglesias 1304fcf5ef2aSThomas Huth switch (cc) { 1305fcf5ef2aSThomas Huth case CC_EQ: 1306fcf5ef2aSThomas Huth case CC_NE: 1307fcf5ef2aSThomas Huth case CC_LT: 1308fcf5ef2aSThomas Huth case CC_LE: 1309fcf5ef2aSThomas Huth case CC_GE: 1310fcf5ef2aSThomas Huth case CC_GT: 13119e6e1828SEdgar E. Iglesias tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); 1312fcf5ef2aSThomas Huth break; 1313fcf5ef2aSThomas Huth default: 1314fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); 1315fcf5ef2aSThomas Huth break; 1316fcf5ef2aSThomas Huth } 1317fcf5ef2aSThomas Huth } 1318fcf5ef2aSThomas Huth 13190f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) 1320fcf5ef2aSThomas Huth { 13210f96e96bSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 1322e956caf2SEdgar E. Iglesias 13230f96e96bSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, 13249b158558SRichard Henderson cpu_btaken, zero, 1325e956caf2SEdgar E. Iglesias pc_true, pc_false); 1326e956caf2SEdgar E. Iglesias 13270f96e96bSRichard Henderson tcg_temp_free_i32(zero); 1328fcf5ef2aSThomas Huth } 1329fcf5ef2aSThomas Huth 1330f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1331f91c60f0SEdgar E. Iglesias { 1332f91c60f0SEdgar E. Iglesias dc->delayed_branch = 2; 1333f91c60f0SEdgar E. Iglesias dc->tb_flags |= D_FLAG; 13347b34f45fSRichard Henderson if (dc->type_b && (dc->tb_flags & IMM_FLAG)) { 13357b34f45fSRichard Henderson dc->tb_flags |= BIMM_FLAG; 13367b34f45fSRichard Henderson } 1337f91c60f0SEdgar E. Iglesias } 1338f91c60f0SEdgar E. Iglesias 1339fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc) 1340fcf5ef2aSThomas Huth { 1341fcf5ef2aSThomas Huth unsigned int cc; 1342fcf5ef2aSThomas Huth unsigned int dslot; 1343fcf5ef2aSThomas Huth 1344fcf5ef2aSThomas Huth cc = EXTRACT_FIELD(dc->ir, 21, 23); 1345fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 25); 1346fcf5ef2aSThomas Huth 1347fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1348fcf5ef2aSThomas Huth if (dslot) { 1349f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1350fcf5ef2aSThomas Huth } 1351fcf5ef2aSThomas Huth 1352d7ecb757SRichard Henderson if (dc->type_b) { 1353fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT_CC; 1354d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1355d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1356fcf5ef2aSThomas Huth } else { 1357fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 1358d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1359fcf5ef2aSThomas Huth } 13609b158558SRichard Henderson eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); 1361fcf5ef2aSThomas Huth } 1362fcf5ef2aSThomas Huth 1363fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc) 1364fcf5ef2aSThomas Huth { 1365fcf5ef2aSThomas Huth unsigned int dslot, link, abs, mbar; 1366fcf5ef2aSThomas Huth 1367fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 20); 1368fcf5ef2aSThomas Huth abs = dc->ir & (1 << 19); 1369fcf5ef2aSThomas Huth link = dc->ir & (1 << 18); 1370fcf5ef2aSThomas Huth 1371fcf5ef2aSThomas Huth /* Memory barrier. */ 1372fcf5ef2aSThomas Huth mbar = (dc->ir >> 16) & 31; 1373fcf5ef2aSThomas Huth if (mbar == 2 && dc->imm == 4) { 1374badcbf9dSEdgar E. Iglesias uint16_t mbar_imm = dc->rd; 1375badcbf9dSEdgar E. Iglesias 13763f172744SEdgar E. Iglesias /* Data access memory barrier. */ 13773f172744SEdgar E. Iglesias if ((mbar_imm & 2) == 0) { 13783f172744SEdgar E. Iglesias tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 13793f172744SEdgar E. Iglesias } 13803f172744SEdgar E. Iglesias 1381fcf5ef2aSThomas Huth /* mbar IMM & 16 decodes to sleep. */ 1382badcbf9dSEdgar E. Iglesias if (mbar_imm & 16) { 138341ba37c4SRichard Henderson TCGv_i32 tmp_1; 1384fcf5ef2aSThomas Huth 1385b4919e7dSEdgar E. Iglesias if (trap_userspace(dc, true)) { 1386b4919e7dSEdgar E. Iglesias /* Sleep is a privileged instruction. */ 1387b4919e7dSEdgar E. Iglesias return; 1388b4919e7dSEdgar E. Iglesias } 1389b4919e7dSEdgar E. Iglesias 1390fcf5ef2aSThomas Huth t_sync_flags(dc); 139141ba37c4SRichard Henderson 139241ba37c4SRichard Henderson tmp_1 = tcg_const_i32(1); 1393fcf5ef2aSThomas Huth tcg_gen_st_i32(tmp_1, cpu_env, 1394fcf5ef2aSThomas Huth -offsetof(MicroBlazeCPU, env) 1395fcf5ef2aSThomas Huth +offsetof(CPUState, halted)); 1396fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp_1); 139741ba37c4SRichard Henderson 1398d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 139941ba37c4SRichard Henderson 140041ba37c4SRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1401fcf5ef2aSThomas Huth return; 1402fcf5ef2aSThomas Huth } 1403fcf5ef2aSThomas Huth /* Break the TB. */ 1404fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 1405fcf5ef2aSThomas Huth return; 1406fcf5ef2aSThomas Huth } 1407fcf5ef2aSThomas Huth 1408d7ecb757SRichard Henderson if (abs && link && !dslot) { 1409d7ecb757SRichard Henderson if (dc->type_b) { 1410d7ecb757SRichard Henderson /* BRKI */ 1411d7ecb757SRichard Henderson uint32_t imm = dec_alu_typeb_imm(dc); 1412d7ecb757SRichard Henderson if (trap_userspace(dc, imm != 8 && imm != 0x18)) { 1413d7ecb757SRichard Henderson return; 1414d7ecb757SRichard Henderson } 1415d7ecb757SRichard Henderson } else { 1416d7ecb757SRichard Henderson /* BRK */ 1417d7ecb757SRichard Henderson if (trap_userspace(dc, true)) { 1418d7ecb757SRichard Henderson return; 1419d7ecb757SRichard Henderson } 1420d7ecb757SRichard Henderson } 1421d7ecb757SRichard Henderson } 1422d7ecb757SRichard Henderson 1423fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1424fcf5ef2aSThomas Huth if (dslot) { 1425f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1426fcf5ef2aSThomas Huth } 1427d7ecb757SRichard Henderson if (link && dc->rd) { 1428d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1429d7ecb757SRichard Henderson } 1430fcf5ef2aSThomas Huth 1431fcf5ef2aSThomas Huth if (abs) { 1432d7ecb757SRichard Henderson if (dc->type_b) { 1433d7ecb757SRichard Henderson uint32_t dest = dec_alu_typeb_imm(dc); 1434d7ecb757SRichard Henderson 1435d7ecb757SRichard Henderson dc->jmp = JMP_DIRECT; 1436d7ecb757SRichard Henderson dc->jmp_pc = dest; 1437d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dest); 1438fcf5ef2aSThomas Huth if (link && !dslot) { 1439d7ecb757SRichard Henderson switch (dest) { 1440d7ecb757SRichard Henderson case 8: 1441d7ecb757SRichard Henderson case 0x18: 1442d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 1443d7ecb757SRichard Henderson break; 1444d7ecb757SRichard Henderson case 0: 1445d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1446d7ecb757SRichard Henderson break; 1447d7ecb757SRichard Henderson } 1448d7ecb757SRichard Henderson } 1449d7ecb757SRichard Henderson } else { 1450d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1451d7ecb757SRichard Henderson tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]); 1452d7ecb757SRichard Henderson if (link && !dslot) { 145341ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 145441ba37c4SRichard Henderson } 1455fcf5ef2aSThomas Huth } 1456d7ecb757SRichard Henderson } else if (dc->type_b) { 1457fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT; 1458d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1459d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1460fcf5ef2aSThomas Huth } else { 1461d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1462d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1463d7ecb757SRichard Henderson } 14649b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 1465fcf5ef2aSThomas Huth } 1466fcf5ef2aSThomas Huth 1467fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc) 1468fcf5ef2aSThomas Huth { 1469cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1470cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1471cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 14723e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 14730a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 14740a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1475cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1476fcf5ef2aSThomas Huth 1477cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1478cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1479fcf5ef2aSThomas Huth msr_write(dc, t1); 1480cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1481cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1482fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1483fcf5ef2aSThomas Huth } 1484fcf5ef2aSThomas Huth 1485fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc) 1486fcf5ef2aSThomas Huth { 1487cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1488cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1489cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 14903e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 14910a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1492cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1493cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1494fcf5ef2aSThomas Huth 1495cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1496cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1497fcf5ef2aSThomas Huth msr_write(dc, t1); 1498cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1499cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1500fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1501fcf5ef2aSThomas Huth } 1502fcf5ef2aSThomas Huth 1503fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc) 1504fcf5ef2aSThomas Huth { 1505cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1506cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1507cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1508fcf5ef2aSThomas Huth 15093e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 15100a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1511cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1512cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1513cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1514fcf5ef2aSThomas Huth 1515cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1516cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1517fcf5ef2aSThomas Huth msr_write(dc, t1); 1518cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1519cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1520fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1521fcf5ef2aSThomas Huth } 1522fcf5ef2aSThomas Huth 1523fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc) 1524fcf5ef2aSThomas Huth { 1525fcf5ef2aSThomas Huth unsigned int b_bit, i_bit, e_bit; 1526fcf5ef2aSThomas Huth 1527fcf5ef2aSThomas Huth i_bit = dc->ir & (1 << 21); 1528fcf5ef2aSThomas Huth b_bit = dc->ir & (1 << 22); 1529fcf5ef2aSThomas Huth e_bit = dc->ir & (1 << 23); 1530fcf5ef2aSThomas Huth 1531bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1532bdfc1e88SEdgar E. Iglesias return; 1533bdfc1e88SEdgar E. Iglesias } 1534bdfc1e88SEdgar E. Iglesias 1535f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1536fcf5ef2aSThomas Huth 1537fcf5ef2aSThomas Huth if (i_bit) { 1538fcf5ef2aSThomas Huth dc->tb_flags |= DRTI_FLAG; 1539fcf5ef2aSThomas Huth } else if (b_bit) { 1540fcf5ef2aSThomas Huth dc->tb_flags |= DRTB_FLAG; 1541fcf5ef2aSThomas Huth } else if (e_bit) { 1542fcf5ef2aSThomas Huth dc->tb_flags |= DRTE_FLAG; 154311105d67SRichard Henderson } 1544fcf5ef2aSThomas Huth 1545fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 15469b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 15470f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 1548fcf5ef2aSThomas Huth } 1549fcf5ef2aSThomas Huth 1550fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc) 1551fcf5ef2aSThomas Huth { 15529ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 1553fcf5ef2aSThomas Huth return; 1554fcf5ef2aSThomas Huth } 1555d4705ae0SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", 1556d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, dc->opcode); 1557fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1558fcf5ef2aSThomas Huth } 1559fcf5ef2aSThomas Huth 1560fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 1561fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc) 1562fcf5ef2aSThomas Huth { 1563fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1564fcf5ef2aSThomas Huth int ctrl; 1565fcf5ef2aSThomas Huth 1566bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 1567fcf5ef2aSThomas Huth return; 1568fcf5ef2aSThomas Huth } 1569fcf5ef2aSThomas Huth 1570cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 1571fcf5ef2aSThomas Huth if (dc->type_b) { 1572cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 1573fcf5ef2aSThomas Huth ctrl = dc->imm >> 10; 1574fcf5ef2aSThomas Huth } else { 1575cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 1576fcf5ef2aSThomas Huth ctrl = dc->imm >> 5; 1577fcf5ef2aSThomas Huth } 1578fcf5ef2aSThomas Huth 1579cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 1580fcf5ef2aSThomas Huth 1581fcf5ef2aSThomas Huth if (dc->rd == 0) { 1582fcf5ef2aSThomas Huth gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 1583fcf5ef2aSThomas Huth } else { 1584fcf5ef2aSThomas Huth gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 1585fcf5ef2aSThomas Huth } 1586cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1587cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 1588fcf5ef2aSThomas Huth } 1589fcf5ef2aSThomas Huth 1590fcf5ef2aSThomas Huth static struct decoder_info { 1591fcf5ef2aSThomas Huth struct { 1592fcf5ef2aSThomas Huth uint32_t bits; 1593fcf5ef2aSThomas Huth uint32_t mask; 1594fcf5ef2aSThomas Huth }; 1595fcf5ef2aSThomas Huth void (*dec)(DisasContext *dc); 1596fcf5ef2aSThomas Huth } decinfo[] = { 1597fcf5ef2aSThomas Huth {DEC_BR, dec_br}, 1598fcf5ef2aSThomas Huth {DEC_BCC, dec_bcc}, 1599fcf5ef2aSThomas Huth {DEC_RTS, dec_rts}, 1600fcf5ef2aSThomas Huth {DEC_MSR, dec_msr}, 1601fcf5ef2aSThomas Huth {DEC_STREAM, dec_stream}, 1602fcf5ef2aSThomas Huth {{0, 0}, dec_null} 1603fcf5ef2aSThomas Huth }; 1604fcf5ef2aSThomas Huth 160544d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir) 1606fcf5ef2aSThomas Huth { 1607fcf5ef2aSThomas Huth int i; 1608fcf5ef2aSThomas Huth 1609fcf5ef2aSThomas Huth dc->ir = ir; 1610fcf5ef2aSThomas Huth 1611fcf5ef2aSThomas Huth /* bit 2 seems to indicate insn type. */ 1612fcf5ef2aSThomas Huth dc->type_b = ir & (1 << 29); 1613fcf5ef2aSThomas Huth 1614fcf5ef2aSThomas Huth dc->opcode = EXTRACT_FIELD(ir, 26, 31); 1615fcf5ef2aSThomas Huth dc->rd = EXTRACT_FIELD(ir, 21, 25); 1616fcf5ef2aSThomas Huth dc->ra = EXTRACT_FIELD(ir, 16, 20); 1617fcf5ef2aSThomas Huth dc->rb = EXTRACT_FIELD(ir, 11, 15); 1618fcf5ef2aSThomas Huth dc->imm = EXTRACT_FIELD(ir, 0, 15); 1619fcf5ef2aSThomas Huth 1620fcf5ef2aSThomas Huth /* Large switch for all insns. */ 1621fcf5ef2aSThomas Huth for (i = 0; i < ARRAY_SIZE(decinfo); i++) { 1622fcf5ef2aSThomas Huth if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { 1623fcf5ef2aSThomas Huth decinfo[i].dec(dc); 1624fcf5ef2aSThomas Huth break; 1625fcf5ef2aSThomas Huth } 1626fcf5ef2aSThomas Huth } 1627fcf5ef2aSThomas Huth } 1628fcf5ef2aSThomas Huth 1629372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1630fcf5ef2aSThomas Huth { 1631372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1632372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1633372122e3SRichard Henderson int bound; 1634fcf5ef2aSThomas Huth 1635fcf5ef2aSThomas Huth dc->cpu = cpu; 1636683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags; 1637fcf5ef2aSThomas Huth dc->delayed_branch = !!(dc->tb_flags & D_FLAG); 1638372122e3SRichard Henderson dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; 1639fcf5ef2aSThomas Huth dc->cpustate_changed = 0; 1640fcf5ef2aSThomas Huth dc->abort_at_next_insn = 0; 1641d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 164220800179SRichard Henderson dc->r0 = NULL; 164320800179SRichard Henderson dc->r0_set = false; 1644287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 1645fcf5ef2aSThomas Huth 1646372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1647372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1648fcf5ef2aSThomas Huth } 1649fcf5ef2aSThomas Huth 1650372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1651fcf5ef2aSThomas Huth { 1652fcf5ef2aSThomas Huth } 1653fcf5ef2aSThomas Huth 1654372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1655372122e3SRichard Henderson { 1656683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1657683a247eSRichard Henderson 1658683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); 1659683a247eSRichard Henderson dc->insn_start = tcg_last_op(); 1660372122e3SRichard Henderson } 1661fcf5ef2aSThomas Huth 1662372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1663372122e3SRichard Henderson const CPUBreakpoint *bp) 1664372122e3SRichard Henderson { 1665372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1666372122e3SRichard Henderson 1667372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1668372122e3SRichard Henderson 1669372122e3SRichard Henderson /* 1670372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1671372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1672372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1673372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1674372122e3SRichard Henderson */ 1675372122e3SRichard Henderson dc->base.pc_next += 4; 1676372122e3SRichard Henderson return true; 1677372122e3SRichard Henderson } 1678372122e3SRichard Henderson 1679372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1680372122e3SRichard Henderson { 1681372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1682372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 168344d1432bSRichard Henderson uint32_t ir; 1684372122e3SRichard Henderson 1685372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1686372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1687372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1688372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1689fcf5ef2aSThomas Huth } 1690fcf5ef2aSThomas Huth 1691fcf5ef2aSThomas Huth dc->clear_imm = 1; 169244d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 169344d1432bSRichard Henderson if (!decode(dc, ir)) { 169444d1432bSRichard Henderson old_decode(dc, ir); 169544d1432bSRichard Henderson } 169620800179SRichard Henderson 169720800179SRichard Henderson if (dc->r0) { 169820800179SRichard Henderson tcg_temp_free_i32(dc->r0); 169920800179SRichard Henderson dc->r0 = NULL; 170020800179SRichard Henderson dc->r0_set = false; 170120800179SRichard Henderson } 170220800179SRichard Henderson 1703d7ecb757SRichard Henderson if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { 1704fcf5ef2aSThomas Huth dc->tb_flags &= ~IMM_FLAG; 1705d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1706372122e3SRichard Henderson } 1707d4705ae0SRichard Henderson dc->base.pc_next += 4; 1708fcf5ef2aSThomas Huth 1709372122e3SRichard Henderson if (dc->delayed_branch && --dc->delayed_branch == 0) { 1710372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 1711fcf5ef2aSThomas Huth do_rti(dc); 1712372122e3SRichard Henderson } 1713372122e3SRichard Henderson if (dc->tb_flags & DRTB_FLAG) { 1714fcf5ef2aSThomas Huth do_rtb(dc); 1715372122e3SRichard Henderson } 1716372122e3SRichard Henderson if (dc->tb_flags & DRTE_FLAG) { 1717fcf5ef2aSThomas Huth do_rte(dc); 1718372122e3SRichard Henderson } 1719fcf5ef2aSThomas Huth /* Clear the delay slot flag. */ 1720fcf5ef2aSThomas Huth dc->tb_flags &= ~D_FLAG; 1721372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1722372122e3SRichard Henderson } 1723372122e3SRichard Henderson 1724372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1725372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1726372122e3SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1727372122e3SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1728372122e3SRichard Henderson } 1729372122e3SRichard Henderson } 1730372122e3SRichard Henderson 1731372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1732372122e3SRichard Henderson { 1733372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1734372122e3SRichard Henderson 1735372122e3SRichard Henderson assert(!dc->abort_at_next_insn); 1736372122e3SRichard Henderson 1737372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1738372122e3SRichard Henderson /* We have already exited the TB. */ 1739372122e3SRichard Henderson return; 1740372122e3SRichard Henderson } 1741372122e3SRichard Henderson 1742372122e3SRichard Henderson t_sync_flags(dc); 1743372122e3SRichard Henderson if (dc->tb_flags & D_FLAG) { 1744372122e3SRichard Henderson sync_jmpstate(dc); 1745372122e3SRichard Henderson dc->jmp = JMP_NOJMP; 1746372122e3SRichard Henderson } 1747372122e3SRichard Henderson 1748372122e3SRichard Henderson switch (dc->base.is_jmp) { 1749372122e3SRichard Henderson case DISAS_TOO_MANY: 1750372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1751372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1752372122e3SRichard Henderson return; 1753372122e3SRichard Henderson 1754372122e3SRichard Henderson case DISAS_UPDATE: 1755372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1756372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1757372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1758372122e3SRichard Henderson } else { 1759372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1760372122e3SRichard Henderson } 1761372122e3SRichard Henderson return; 1762372122e3SRichard Henderson 1763372122e3SRichard Henderson case DISAS_JUMP: 1764372122e3SRichard Henderson switch (dc->jmp) { 1765372122e3SRichard Henderson case JMP_INDIRECT: 1766372122e3SRichard Henderson { 1767d4705ae0SRichard Henderson TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); 17680f96e96bSRichard Henderson eval_cond_jmp(dc, cpu_btarget, tmp_pc); 17690f96e96bSRichard Henderson tcg_temp_free_i32(tmp_pc); 1770372122e3SRichard Henderson 1771372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1772372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1773372122e3SRichard Henderson } else { 1774372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1775372122e3SRichard Henderson } 1776372122e3SRichard Henderson } 1777372122e3SRichard Henderson return; 1778372122e3SRichard Henderson 1779372122e3SRichard Henderson case JMP_DIRECT_CC: 1780372122e3SRichard Henderson { 1781fcf5ef2aSThomas Huth TCGLabel *l1 = gen_new_label(); 17829b158558SRichard Henderson tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); 1783d4705ae0SRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1784fcf5ef2aSThomas Huth gen_set_label(l1); 1785372122e3SRichard Henderson } 1786372122e3SRichard Henderson /* fall through */ 1787372122e3SRichard Henderson 1788372122e3SRichard Henderson case JMP_DIRECT: 1789fcf5ef2aSThomas Huth gen_goto_tb(dc, 0, dc->jmp_pc); 1790372122e3SRichard Henderson return; 1791fcf5ef2aSThomas Huth } 1792372122e3SRichard Henderson /* fall through */ 1793fcf5ef2aSThomas Huth 1794a2b80dbdSRichard Henderson default: 1795a2b80dbdSRichard Henderson g_assert_not_reached(); 1796fcf5ef2aSThomas Huth } 1797fcf5ef2aSThomas Huth } 1798fcf5ef2aSThomas Huth 1799372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1800372122e3SRichard Henderson { 1801372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1802372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 1803fcf5ef2aSThomas Huth } 1804372122e3SRichard Henderson 1805372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1806372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1807372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1808372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1809372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1810372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1811372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1812372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1813372122e3SRichard Henderson }; 1814372122e3SRichard Henderson 1815372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1816372122e3SRichard Henderson { 1817372122e3SRichard Henderson DisasContext dc; 1818372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 1819fcf5ef2aSThomas Huth } 1820fcf5ef2aSThomas Huth 182190c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1822fcf5ef2aSThomas Huth { 1823fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1824fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 1825fcf5ef2aSThomas Huth int i; 1826fcf5ef2aSThomas Huth 182790c84c56SMarkus Armbruster if (!env) { 1828fcf5ef2aSThomas Huth return; 182990c84c56SMarkus Armbruster } 1830fcf5ef2aSThomas Huth 18310f96e96bSRichard Henderson qemu_fprintf(f, "IN: PC=%x %s\n", 183276e8187dSRichard Henderson env->pc, lookup_symbol(env->pc)); 18336efd5599SRichard Henderson qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " 1834eb2022b7SRichard Henderson "imm=%x iflags=%x fsr=%x rbtr=%x\n", 183578e9caf2SRichard Henderson env->msr, env->esr, env->ear, 1836eb2022b7SRichard Henderson env->imm, env->iflags, env->fsr, env->btr); 18370f96e96bSRichard Henderson qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 1838fcf5ef2aSThomas Huth env->btaken, env->btarget, 18392e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18402e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18412e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18422e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18432ead1b18SJoe Komlodi for (i = 0; i < 12; i++) { 18442ead1b18SJoe Komlodi qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); 18452ead1b18SJoe Komlodi if ((i + 1) % 4 == 0) { 18462ead1b18SJoe Komlodi qemu_fprintf(f, "\n"); 18472ead1b18SJoe Komlodi } 18482ead1b18SJoe Komlodi } 1849fcf5ef2aSThomas Huth 18502ead1b18SJoe Komlodi /* Registers that aren't modeled are reported as 0 */ 185139db007eSRichard Henderson qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " 1852af20a93aSRichard Henderson "rtlblo=0 rtlbhi=0\n", env->edr); 18532ead1b18SJoe Komlodi qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); 1854fcf5ef2aSThomas Huth for (i = 0; i < 32; i++) { 185590c84c56SMarkus Armbruster qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); 1856fcf5ef2aSThomas Huth if ((i + 1) % 4 == 0) 185790c84c56SMarkus Armbruster qemu_fprintf(f, "\n"); 1858fcf5ef2aSThomas Huth } 185990c84c56SMarkus Armbruster qemu_fprintf(f, "\n\n"); 1860fcf5ef2aSThomas Huth } 1861fcf5ef2aSThomas Huth 1862fcf5ef2aSThomas Huth void mb_tcg_init(void) 1863fcf5ef2aSThomas Huth { 1864480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1865480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1866fcf5ef2aSThomas Huth 1867480d29a8SRichard Henderson static const struct { 1868480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1869480d29a8SRichard Henderson } i32s[] = { 1870480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1871480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1872480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1873480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1874480d29a8SRichard Henderson 1875480d29a8SRichard Henderson SP(pc), 1876480d29a8SRichard Henderson SP(msr), 18771074c0fbSRichard Henderson SP(msr_c), 1878480d29a8SRichard Henderson SP(imm), 1879480d29a8SRichard Henderson SP(iflags), 1880480d29a8SRichard Henderson SP(btaken), 1881480d29a8SRichard Henderson SP(btarget), 1882480d29a8SRichard Henderson SP(res_val), 1883480d29a8SRichard Henderson }; 1884480d29a8SRichard Henderson 1885480d29a8SRichard Henderson #undef R 1886480d29a8SRichard Henderson #undef SP 1887480d29a8SRichard Henderson 1888480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1889480d29a8SRichard Henderson *i32s[i].var = 1890480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1891fcf5ef2aSThomas Huth } 189276e8187dSRichard Henderson 1893480d29a8SRichard Henderson cpu_res_addr = 1894480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1895fcf5ef2aSThomas Huth } 1896fcf5ef2aSThomas Huth 1897fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1898fcf5ef2aSThomas Huth target_ulong *data) 1899fcf5ef2aSThomas Huth { 190076e8187dSRichard Henderson env->pc = data[0]; 1901683a247eSRichard Henderson env->iflags = data[1]; 1902fcf5ef2aSThomas Huth } 1903