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 "exec/cpu_ldst.h" 28fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 2977fc6f5eSLluís Vilanova #include "exec/translator.h" 3090c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 31fcf5ef2aSThomas Huth 32fcf5ef2aSThomas Huth #include "trace-tcg.h" 33fcf5ef2aSThomas Huth #include "exec/log.h" 34fcf5ef2aSThomas Huth 35fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 36fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 37fcf5ef2aSThomas Huth 3877fc6f5eSLluís Vilanova /* is_jmp field values */ 3977fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 4017e77796SRichard Henderson #define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */ 4177fc6f5eSLluís Vilanova 42*f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */ 43*f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2 44*f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */ 45*f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3 46*f6278ca9SRichard Henderson 47cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 480f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 493e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 501074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 519b158558SRichard Henderson static TCGv_i32 cpu_imm; 52b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue; 530f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 549b158558SRichard Henderson static TCGv_i32 cpu_iflags; 559b158558SRichard Henderson static TCGv cpu_res_addr; 569b158558SRichard Henderson static TCGv_i32 cpu_res_val; 57fcf5ef2aSThomas Huth 58fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 59fcf5ef2aSThomas Huth 60fcf5ef2aSThomas Huth /* This is the state at translation time. */ 61fcf5ef2aSThomas Huth typedef struct DisasContext { 62d4705ae0SRichard Henderson DisasContextBase base; 63fcf5ef2aSThomas Huth MicroBlazeCPU *cpu; 64fcf5ef2aSThomas Huth 65683a247eSRichard Henderson /* TCG op of the current insn_start. */ 66683a247eSRichard Henderson TCGOp *insn_start; 67683a247eSRichard Henderson 6820800179SRichard Henderson TCGv_i32 r0; 6920800179SRichard Henderson bool r0_set; 7020800179SRichard Henderson 71fcf5ef2aSThomas Huth /* Decoder. */ 72d7ecb757SRichard Henderson uint32_t ext_imm; 73fcf5ef2aSThomas Huth unsigned int cpustate_changed; 74683a247eSRichard Henderson unsigned int tb_flags; 756f9642d7SRichard Henderson unsigned int tb_flags_to_set; 76287b1defSRichard Henderson int mem_index; 77fcf5ef2aSThomas Huth 78b9c58aabSRichard Henderson /* Condition under which to jump, including NEVER and ALWAYS. */ 79b9c58aabSRichard Henderson TCGCond jmp_cond; 80b9c58aabSRichard Henderson 81b9c58aabSRichard Henderson /* Immediate branch-taken destination, or -1 for indirect. */ 82b9c58aabSRichard Henderson uint32_t jmp_dest; 83fcf5ef2aSThomas Huth } DisasContext; 84fcf5ef2aSThomas Huth 8520800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8620800179SRichard Henderson { 8720800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 8820800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 8920800179SRichard Henderson } 9020800179SRichard Henderson return x; 9120800179SRichard Henderson } 9220800179SRichard Henderson 9344d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9444d1432bSRichard Henderson #include "decode-insns.c.inc" 9544d1432bSRichard Henderson 96683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc) 97fcf5ef2aSThomas Huth { 98fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 9988e74b61SRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) { 10088e74b61SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK); 101fcf5ef2aSThomas Huth } 102fcf5ef2aSThomas Huth } 103fcf5ef2aSThomas Huth 10441ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 105fcf5ef2aSThomas Huth { 106fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 107fcf5ef2aSThomas Huth 108fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 109fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 110d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 111fcf5ef2aSThomas Huth } 112fcf5ef2aSThomas Huth 11341ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11441ba37c4SRichard Henderson { 11541ba37c4SRichard Henderson t_sync_flags(dc); 116d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 11741ba37c4SRichard Henderson gen_raise_exception(dc, index); 11841ba37c4SRichard Henderson } 11941ba37c4SRichard Henderson 12041ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12141ba37c4SRichard Henderson { 12241ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12341ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12441ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12541ba37c4SRichard Henderson 12641ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 12741ba37c4SRichard Henderson } 12841ba37c4SRichard Henderson 129fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 130fcf5ef2aSThomas Huth { 131fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 132d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 133fcf5ef2aSThomas Huth #else 134fcf5ef2aSThomas Huth return true; 135fcf5ef2aSThomas Huth #endif 136fcf5ef2aSThomas Huth } 137fcf5ef2aSThomas Huth 138fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 139fcf5ef2aSThomas Huth { 140d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1410b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1420b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1430b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1440b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1450b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 146fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1470f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 148d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 149fcf5ef2aSThomas Huth } else { 1500f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 15107ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 152fcf5ef2aSThomas Huth } 153d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 154fcf5ef2aSThomas Huth } 155fcf5ef2aSThomas Huth 156bdfc1e88SEdgar E. Iglesias /* 1579ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1589ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1599ba8cd45SEdgar E. Iglesias */ 1609ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1619ba8cd45SEdgar E. Iglesias { 1622c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE) 1635143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 16441ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1659ba8cd45SEdgar E. Iglesias } 1669ba8cd45SEdgar E. Iglesias return cond; 1679ba8cd45SEdgar E. Iglesias } 1689ba8cd45SEdgar E. Iglesias 1699ba8cd45SEdgar E. Iglesias /* 170bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 171bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 172bdfc1e88SEdgar E. Iglesias */ 173bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 174bdfc1e88SEdgar E. Iglesias { 175287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX; 176bdfc1e88SEdgar E. Iglesias 1772c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) { 17841ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 179bdfc1e88SEdgar E. Iglesias } 180bdfc1e88SEdgar E. Iglesias return cond_user; 181bdfc1e88SEdgar E. Iglesias } 182bdfc1e88SEdgar E. Iglesias 18320800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 184fcf5ef2aSThomas Huth { 18520800179SRichard Henderson if (likely(reg != 0)) { 18620800179SRichard Henderson return cpu_R[reg]; 187fcf5ef2aSThomas Huth } 18820800179SRichard Henderson if (!dc->r0_set) { 18920800179SRichard Henderson if (dc->r0 == NULL) { 19020800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 191fcf5ef2aSThomas Huth } 19220800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 19320800179SRichard Henderson dc->r0_set = true; 19420800179SRichard Henderson } 19520800179SRichard Henderson return dc->r0; 196fcf5ef2aSThomas Huth } 197fcf5ef2aSThomas Huth 19820800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 19920800179SRichard Henderson { 20020800179SRichard Henderson if (likely(reg != 0)) { 20120800179SRichard Henderson return cpu_R[reg]; 20220800179SRichard Henderson } 20320800179SRichard Henderson if (dc->r0 == NULL) { 20420800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 20520800179SRichard Henderson } 20620800179SRichard Henderson return dc->r0; 207fcf5ef2aSThomas Huth } 208fcf5ef2aSThomas Huth 20920800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 21020800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 21120800179SRichard Henderson { 21220800179SRichard Henderson TCGv_i32 rd, ra, rb; 21320800179SRichard Henderson 21420800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 21520800179SRichard Henderson return true; 216fcf5ef2aSThomas Huth } 21720800179SRichard Henderson 21820800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 21920800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 22020800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 22120800179SRichard Henderson fn(rd, ra, rb); 22220800179SRichard Henderson return true; 22320800179SRichard Henderson } 22420800179SRichard Henderson 22539cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, 22639cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32)) 22739cf3864SRichard Henderson { 22839cf3864SRichard Henderson TCGv_i32 rd, ra; 22939cf3864SRichard Henderson 23039cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) { 23139cf3864SRichard Henderson return true; 23239cf3864SRichard Henderson } 23339cf3864SRichard Henderson 23439cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd); 23539cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra); 23639cf3864SRichard Henderson fn(rd, ra); 23739cf3864SRichard Henderson return true; 23839cf3864SRichard Henderson } 23939cf3864SRichard Henderson 24020800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 24120800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 24220800179SRichard Henderson { 24320800179SRichard Henderson TCGv_i32 rd, ra; 24420800179SRichard Henderson 24520800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 24620800179SRichard Henderson return true; 24720800179SRichard Henderson } 24820800179SRichard Henderson 24920800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 25020800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 25120800179SRichard Henderson fni(rd, ra, arg->imm); 25220800179SRichard Henderson return true; 25320800179SRichard Henderson } 25420800179SRichard Henderson 25520800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 25620800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 25720800179SRichard Henderson { 25820800179SRichard Henderson TCGv_i32 rd, ra, imm; 25920800179SRichard Henderson 26020800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 26120800179SRichard Henderson return true; 26220800179SRichard Henderson } 26320800179SRichard Henderson 26420800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 26520800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 26620800179SRichard Henderson imm = tcg_const_i32(arg->imm); 26720800179SRichard Henderson 26820800179SRichard Henderson fn(rd, ra, imm); 26920800179SRichard Henderson 27020800179SRichard Henderson tcg_temp_free_i32(imm); 27120800179SRichard Henderson return true; 27220800179SRichard Henderson } 27320800179SRichard Henderson 27420800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 27520800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 27620800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 27720800179SRichard Henderson 278607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 279607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 280607f5767SRichard Henderson { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } 281607f5767SRichard Henderson 28239cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 28339cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 28439cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 28539cf3864SRichard Henderson 28639cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 28739cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 28839cf3864SRichard Henderson { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); } 28939cf3864SRichard Henderson 29020800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 29120800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29220800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 29320800179SRichard Henderson 29497955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 29597955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29697955cebSRichard Henderson { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } 29797955cebSRichard Henderson 29820800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 29920800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 30020800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 30120800179SRichard Henderson 302d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 303d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 304d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 305d5aead3dSRichard Henderson 306d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 307d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 308d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 309d5aead3dSRichard Henderson 31020800179SRichard Henderson /* No input carry, but output carry. */ 31120800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 31220800179SRichard Henderson { 31320800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 31420800179SRichard Henderson 31520800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 31620800179SRichard Henderson 31720800179SRichard Henderson tcg_temp_free_i32(zero); 31820800179SRichard Henderson } 31920800179SRichard Henderson 32020800179SRichard Henderson /* Input and output carry. */ 32120800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 32220800179SRichard Henderson { 32320800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 32420800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 32520800179SRichard Henderson 32620800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 32720800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 32820800179SRichard Henderson 32920800179SRichard Henderson tcg_temp_free_i32(tmp); 33020800179SRichard Henderson tcg_temp_free_i32(zero); 33120800179SRichard Henderson } 33220800179SRichard Henderson 33320800179SRichard Henderson /* Input carry, but no output carry. */ 33420800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 33520800179SRichard Henderson { 33620800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 33720800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 33820800179SRichard Henderson } 33920800179SRichard Henderson 34020800179SRichard Henderson DO_TYPEA(add, true, gen_add) 34120800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 34220800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 34320800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 34420800179SRichard Henderson 34520800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 34620800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 34720800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 34820800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 34920800179SRichard Henderson 350cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 351cb0a0a4cSRichard Henderson { 352cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 353cb0a0a4cSRichard Henderson } 354cb0a0a4cSRichard Henderson 355cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 356cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 357cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 358cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 359cb0a0a4cSRichard Henderson 360081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 361081d8e02SRichard Henderson { 362081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 363081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 364081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 365081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 366081d8e02SRichard Henderson } 367081d8e02SRichard Henderson 368081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 369081d8e02SRichard Henderson { 370081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 371081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 372081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 373081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 374081d8e02SRichard Henderson } 375081d8e02SRichard Henderson 376081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 377081d8e02SRichard Henderson { 378081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 379081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 380081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 381081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 382081d8e02SRichard Henderson } 383081d8e02SRichard Henderson 384081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 385081d8e02SRichard Henderson { 386081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 387081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 388081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 389081d8e02SRichard Henderson 390081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 391081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 392081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 393081d8e02SRichard Henderson imm_w, imm_s); 394081d8e02SRichard Henderson } else { 395081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 396081d8e02SRichard Henderson } 397081d8e02SRichard Henderson } 398081d8e02SRichard Henderson 399081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 400081d8e02SRichard Henderson { 401081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 402081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 403081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 404081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 405081d8e02SRichard Henderson 406081d8e02SRichard Henderson if (imm_w < imm_s) { 407081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 408081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 409081d8e02SRichard Henderson imm_w, imm_s); 410081d8e02SRichard Henderson } else { 411081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 412081d8e02SRichard Henderson } 413081d8e02SRichard Henderson } 414081d8e02SRichard Henderson 415081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 416081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 417081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 418081d8e02SRichard Henderson 419081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 420081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 421081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 422081d8e02SRichard Henderson 423081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 424081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 425081d8e02SRichard Henderson 42639cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 42739cf3864SRichard Henderson { 42839cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 42939cf3864SRichard Henderson } 43039cf3864SRichard Henderson 43139cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 43239cf3864SRichard Henderson 43358b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 43458b48b63SRichard Henderson { 43558b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 43658b48b63SRichard Henderson 43758b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 43858b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 43958b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 44058b48b63SRichard Henderson tcg_temp_free_i32(lt); 44158b48b63SRichard Henderson } 44258b48b63SRichard Henderson 44358b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 44458b48b63SRichard Henderson { 44558b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 44658b48b63SRichard Henderson 44758b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 44858b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 44958b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 45058b48b63SRichard Henderson tcg_temp_free_i32(lt); 45158b48b63SRichard Henderson } 45258b48b63SRichard Henderson 45358b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 45458b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 455a2b0b90eSRichard Henderson 456d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 457d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 458d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 459d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 460d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 461d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 462d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 463d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 464d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 465d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 466d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 467d5aead3dSRichard Henderson 468d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 469d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 470d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 471d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 472d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 473d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 474d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 475d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 476d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 477d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 478d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 479d5aead3dSRichard Henderson 480d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 481d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 482d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 483d5aead3dSRichard Henderson 484d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 485d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 486d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 487d5aead3dSRichard Henderson 488d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 489b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 490b1354342SRichard Henderson { 491b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 492b1354342SRichard Henderson } 493b1354342SRichard Henderson 494b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 495b1354342SRichard Henderson { 496b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 497b1354342SRichard Henderson } 498b1354342SRichard Henderson 499b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 500b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 501b1354342SRichard Henderson 502e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 503e64b2e5cSRichard Henderson { 504e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 505e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 5066f9642d7SRichard Henderson dc->tb_flags_to_set = IMM_FLAG; 507e64b2e5cSRichard Henderson return true; 508e64b2e5cSRichard Henderson } 509e64b2e5cSRichard Henderson 51097955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 51197955cebSRichard Henderson { 51297955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 51397955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 51497955cebSRichard Henderson tcg_temp_free_i32(tmp); 51597955cebSRichard Henderson } 51697955cebSRichard Henderson 51797955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 51897955cebSRichard Henderson { 51997955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 52097955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 52197955cebSRichard Henderson tcg_temp_free_i32(tmp); 52297955cebSRichard Henderson } 52397955cebSRichard Henderson 52497955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 52597955cebSRichard Henderson { 52697955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 52797955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 52897955cebSRichard Henderson tcg_temp_free_i32(tmp); 52997955cebSRichard Henderson } 53097955cebSRichard Henderson 53197955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 53297955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 53397955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 53497955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 53597955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 53697955cebSRichard Henderson 537cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 538cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 539cb0a0a4cSRichard Henderson 540607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 541607f5767SRichard Henderson { 542607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 543607f5767SRichard Henderson } 544607f5767SRichard Henderson 545607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 546607f5767SRichard Henderson { 547607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 548607f5767SRichard Henderson } 549607f5767SRichard Henderson 550607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 551607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 552607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 553607f5767SRichard Henderson 554a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 555a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 556a2b0b90eSRichard Henderson { 557a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 558a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 559a2b0b90eSRichard Henderson } 560a2b0b90eSRichard Henderson 561a2b0b90eSRichard Henderson /* Input and output carry. */ 562a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 563a2b0b90eSRichard Henderson { 564a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 565a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 566a2b0b90eSRichard Henderson 567a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 568a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 569a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 570a2b0b90eSRichard Henderson 571a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 572a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 573a2b0b90eSRichard Henderson } 574a2b0b90eSRichard Henderson 575a2b0b90eSRichard Henderson /* No input or output carry. */ 576a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 577a2b0b90eSRichard Henderson { 578a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 579a2b0b90eSRichard Henderson } 580a2b0b90eSRichard Henderson 581a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 582a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 583a2b0b90eSRichard Henderson { 584a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 585a2b0b90eSRichard Henderson 586a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 587a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 588a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 589a2b0b90eSRichard Henderson 590a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 591a2b0b90eSRichard Henderson } 592a2b0b90eSRichard Henderson 593a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 594a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 595a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 596a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 597a2b0b90eSRichard Henderson 598a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 599a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 600a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 601a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 602a2b0b90eSRichard Henderson 60339cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 60439cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 60539cf3864SRichard Henderson 60639cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 60739cf3864SRichard Henderson { 60839cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 60939cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 61039cf3864SRichard Henderson } 61139cf3864SRichard Henderson 61239cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 61339cf3864SRichard Henderson { 61439cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 61539cf3864SRichard Henderson 61639cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 61739cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 61839cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 61939cf3864SRichard Henderson 62039cf3864SRichard Henderson tcg_temp_free_i32(tmp); 62139cf3864SRichard Henderson } 62239cf3864SRichard Henderson 62339cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 62439cf3864SRichard Henderson { 62539cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 62639cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 62739cf3864SRichard Henderson } 62839cf3864SRichard Henderson 62939cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 63039cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 63139cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 63239cf3864SRichard Henderson 63339cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 63439cf3864SRichard Henderson { 63539cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 63639cf3864SRichard Henderson } 63739cf3864SRichard Henderson 63839cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 63939cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 64039cf3864SRichard Henderson 64139cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 64239cf3864SRichard Henderson { 64339cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 64439cf3864SRichard Henderson trap_userspace(dc, true); 64539cf3864SRichard Henderson return true; 64639cf3864SRichard Henderson } 64739cf3864SRichard Henderson 648cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 649cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 650cb0a0a4cSRichard Henderson 651d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 652d8e59c4aSRichard Henderson { 653d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 654d8e59c4aSRichard Henderson 655d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 656d8e59c4aSRichard Henderson if (ra && rb) { 657d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 658d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 659d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 660d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 661d8e59c4aSRichard Henderson } else if (ra) { 662d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 663d8e59c4aSRichard Henderson } else if (rb) { 664d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 665d8e59c4aSRichard Henderson } else { 666d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 667d8e59c4aSRichard Henderson } 668d8e59c4aSRichard Henderson 669d8e59c4aSRichard Henderson if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) { 670d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 671d8e59c4aSRichard Henderson } 672d8e59c4aSRichard Henderson return ret; 673d8e59c4aSRichard Henderson } 674d8e59c4aSRichard Henderson 675d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 676d8e59c4aSRichard Henderson { 677d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 678d8e59c4aSRichard Henderson 679d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 680d8e59c4aSRichard Henderson if (ra) { 681d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 682d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 683d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 684d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 685d8e59c4aSRichard Henderson } else { 686d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 687d8e59c4aSRichard Henderson } 688d8e59c4aSRichard Henderson 689d8e59c4aSRichard Henderson if (ra == 1 && dc->cpu->cfg.stackprot) { 690d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 691d8e59c4aSRichard Henderson } 692d8e59c4aSRichard Henderson return ret; 693d8e59c4aSRichard Henderson } 694d8e59c4aSRichard Henderson 69519f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY 696d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 697d8e59c4aSRichard Henderson { 698d8e59c4aSRichard Henderson int addr_size = dc->cpu->cfg.addr_size; 699d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 700d8e59c4aSRichard Henderson 701d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 702d8e59c4aSRichard Henderson if (rb) { 703d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 704d8e59c4aSRichard Henderson } else { 705d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 706d8e59c4aSRichard Henderson } 707d8e59c4aSRichard Henderson } else { 708d8e59c4aSRichard Henderson if (rb) { 709d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 710d8e59c4aSRichard Henderson } else { 711d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 712d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 713d8e59c4aSRichard Henderson } 714d8e59c4aSRichard Henderson if (addr_size < 64) { 715d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 716d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 717d8e59c4aSRichard Henderson } 718d8e59c4aSRichard Henderson } 719d8e59c4aSRichard Henderson return ret; 720d8e59c4aSRichard Henderson } 72119f27b6cSRichard Henderson #endif 722d8e59c4aSRichard Henderson 723ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd, 724ab0c8d0fSRichard Henderson MemOp size, bool store) 725ab0c8d0fSRichard Henderson { 726ab0c8d0fSRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); 727ab0c8d0fSRichard Henderson 728ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG; 729ab0c8d0fSRichard Henderson iflags |= rd << 5; 730ab0c8d0fSRichard Henderson iflags |= store * ESR_S; 731ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W; 732ab0c8d0fSRichard Henderson 733ab0c8d0fSRichard Henderson tcg_set_insn_start_param(dc->insn_start, 1, iflags); 734ab0c8d0fSRichard Henderson } 735ab0c8d0fSRichard Henderson 736d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 737d8e59c4aSRichard Henderson int mem_index, bool rev) 738d8e59c4aSRichard Henderson { 739d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 740d8e59c4aSRichard Henderson 741d8e59c4aSRichard Henderson /* 742d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 743d8e59c4aSRichard Henderson * 744d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 745d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 746d8e59c4aSRichard Henderson */ 747d8e59c4aSRichard Henderson if (rev) { 748d8e59c4aSRichard Henderson if (size > MO_8) { 749d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 750d8e59c4aSRichard Henderson } 751d8e59c4aSRichard Henderson if (size < MO_32) { 752d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 753d8e59c4aSRichard Henderson } 754d8e59c4aSRichard Henderson } 755d8e59c4aSRichard Henderson 756ab0c8d0fSRichard Henderson if (size > MO_8 && 757ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 758ab0c8d0fSRichard Henderson dc->cpu->cfg.unaligned_exceptions) { 759ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false); 760ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 761d8e59c4aSRichard Henderson } 762d8e59c4aSRichard Henderson 763ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); 764d8e59c4aSRichard Henderson 765d8e59c4aSRichard Henderson tcg_temp_free(addr); 766d8e59c4aSRichard Henderson return true; 767d8e59c4aSRichard Henderson } 768d8e59c4aSRichard Henderson 769d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 770d8e59c4aSRichard Henderson { 771d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 772d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 773d8e59c4aSRichard Henderson } 774d8e59c4aSRichard Henderson 775d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 776d8e59c4aSRichard Henderson { 777d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 778d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 779d8e59c4aSRichard Henderson } 780d8e59c4aSRichard Henderson 781d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 782d8e59c4aSRichard Henderson { 783d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 784d8e59c4aSRichard Henderson return true; 785d8e59c4aSRichard Henderson } 78619f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 78719f27b6cSRichard Henderson return true; 78819f27b6cSRichard Henderson #else 789d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 790d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 79119f27b6cSRichard Henderson #endif 792d8e59c4aSRichard Henderson } 793d8e59c4aSRichard Henderson 794d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 795d8e59c4aSRichard Henderson { 796d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 797d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 798d8e59c4aSRichard Henderson } 799d8e59c4aSRichard Henderson 800d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 801d8e59c4aSRichard Henderson { 802d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 803d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 804d8e59c4aSRichard Henderson } 805d8e59c4aSRichard Henderson 806d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 807d8e59c4aSRichard Henderson { 808d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 809d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 810d8e59c4aSRichard Henderson } 811d8e59c4aSRichard Henderson 812d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 813d8e59c4aSRichard Henderson { 814d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 815d8e59c4aSRichard Henderson return true; 816d8e59c4aSRichard Henderson } 81719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 81819f27b6cSRichard Henderson return true; 81919f27b6cSRichard Henderson #else 820d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 821d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 82219f27b6cSRichard Henderson #endif 823d8e59c4aSRichard Henderson } 824d8e59c4aSRichard Henderson 825d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 826d8e59c4aSRichard Henderson { 827d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 828d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 829d8e59c4aSRichard Henderson } 830d8e59c4aSRichard Henderson 831d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 832d8e59c4aSRichard Henderson { 833d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 834d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 835d8e59c4aSRichard Henderson } 836d8e59c4aSRichard Henderson 837d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 838d8e59c4aSRichard Henderson { 839d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 840d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 841d8e59c4aSRichard Henderson } 842d8e59c4aSRichard Henderson 843d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 844d8e59c4aSRichard Henderson { 845d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 846d8e59c4aSRichard Henderson return true; 847d8e59c4aSRichard Henderson } 84819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 84919f27b6cSRichard Henderson return true; 85019f27b6cSRichard Henderson #else 851d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 852d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 85319f27b6cSRichard Henderson #endif 854d8e59c4aSRichard Henderson } 855d8e59c4aSRichard Henderson 856d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg) 857d8e59c4aSRichard Henderson { 858d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 859d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 860d8e59c4aSRichard Henderson } 861d8e59c4aSRichard Henderson 862d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg) 863d8e59c4aSRichard Henderson { 864d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 865d8e59c4aSRichard Henderson 866d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */ 867d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 868d8e59c4aSRichard Henderson 869d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); 870d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 871d8e59c4aSRichard Henderson tcg_temp_free(addr); 872d8e59c4aSRichard Henderson 873d8e59c4aSRichard Henderson if (arg->rd) { 874d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 875d8e59c4aSRichard Henderson } 876d8e59c4aSRichard Henderson 877d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 878d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 879d8e59c4aSRichard Henderson return true; 880d8e59c4aSRichard Henderson } 881d8e59c4aSRichard Henderson 882d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 883d8e59c4aSRichard Henderson int mem_index, bool rev) 884d8e59c4aSRichard Henderson { 885d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 886d8e59c4aSRichard Henderson 887d8e59c4aSRichard Henderson /* 888d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 889d8e59c4aSRichard Henderson * 890d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 891d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 892d8e59c4aSRichard Henderson */ 893d8e59c4aSRichard Henderson if (rev) { 894d8e59c4aSRichard Henderson if (size > MO_8) { 895d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 896d8e59c4aSRichard Henderson } 897d8e59c4aSRichard Henderson if (size < MO_32) { 898d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 899d8e59c4aSRichard Henderson } 900d8e59c4aSRichard Henderson } 901d8e59c4aSRichard Henderson 902ab0c8d0fSRichard Henderson if (size > MO_8 && 903ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 904ab0c8d0fSRichard Henderson dc->cpu->cfg.unaligned_exceptions) { 905ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true); 906ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 907d8e59c4aSRichard Henderson } 908d8e59c4aSRichard Henderson 909ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 910ab0c8d0fSRichard Henderson 911d8e59c4aSRichard Henderson tcg_temp_free(addr); 912d8e59c4aSRichard Henderson return true; 913d8e59c4aSRichard Henderson } 914d8e59c4aSRichard Henderson 915d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 916d8e59c4aSRichard Henderson { 917d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 918d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 919d8e59c4aSRichard Henderson } 920d8e59c4aSRichard Henderson 921d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 922d8e59c4aSRichard Henderson { 923d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 924d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 925d8e59c4aSRichard Henderson } 926d8e59c4aSRichard Henderson 927d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 928d8e59c4aSRichard Henderson { 929d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 930d8e59c4aSRichard Henderson return true; 931d8e59c4aSRichard Henderson } 93219f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 93319f27b6cSRichard Henderson return true; 93419f27b6cSRichard Henderson #else 935d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 936d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 93719f27b6cSRichard Henderson #endif 938d8e59c4aSRichard Henderson } 939d8e59c4aSRichard Henderson 940d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 941d8e59c4aSRichard Henderson { 942d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 943d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 944d8e59c4aSRichard Henderson } 945d8e59c4aSRichard Henderson 946d8e59c4aSRichard Henderson static bool trans_sh(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_TEUW, dc->mem_index, false); 950d8e59c4aSRichard Henderson } 951d8e59c4aSRichard Henderson 952d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 953d8e59c4aSRichard Henderson { 954d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 955d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 956d8e59c4aSRichard Henderson } 957d8e59c4aSRichard Henderson 958d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 959d8e59c4aSRichard Henderson { 960d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 961d8e59c4aSRichard Henderson return true; 962d8e59c4aSRichard Henderson } 96319f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 96419f27b6cSRichard Henderson return true; 96519f27b6cSRichard Henderson #else 966d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 967d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 96819f27b6cSRichard Henderson #endif 969d8e59c4aSRichard Henderson } 970d8e59c4aSRichard Henderson 971d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 972d8e59c4aSRichard Henderson { 973d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 974d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 975d8e59c4aSRichard Henderson } 976d8e59c4aSRichard Henderson 977d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 978d8e59c4aSRichard Henderson { 979d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 980d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 981d8e59c4aSRichard Henderson } 982d8e59c4aSRichard Henderson 983d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 984d8e59c4aSRichard Henderson { 985d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 986d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 987d8e59c4aSRichard Henderson } 988d8e59c4aSRichard Henderson 989d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 990d8e59c4aSRichard Henderson { 991d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 992d8e59c4aSRichard Henderson return true; 993d8e59c4aSRichard Henderson } 99419f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 99519f27b6cSRichard Henderson return true; 99619f27b6cSRichard Henderson #else 997d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 998d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 99919f27b6cSRichard Henderson #endif 1000d8e59c4aSRichard Henderson } 1001d8e59c4aSRichard Henderson 1002d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 1003d8e59c4aSRichard Henderson { 1004d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 1005d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 1006d8e59c4aSRichard Henderson } 1007d8e59c4aSRichard Henderson 1008d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 1009d8e59c4aSRichard Henderson { 1010d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1011d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 1012d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 1013d8e59c4aSRichard Henderson TCGv_i32 tval; 1014d8e59c4aSRichard Henderson 1015d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 1016d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1017d8e59c4aSRichard Henderson 1018d8e59c4aSRichard Henderson /* 1019d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 1020d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 1021d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 1022d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 1023d8e59c4aSRichard Henderson */ 1024d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 1025d8e59c4aSRichard Henderson tcg_temp_free(addr); 1026d8e59c4aSRichard Henderson 1027d8e59c4aSRichard Henderson /* 1028d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 1029d8e59c4aSRichard Henderson * the reserved location. 1030d8e59c4aSRichard Henderson */ 1031d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1032d8e59c4aSRichard Henderson 1033d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1034d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1035d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1036d8e59c4aSRichard Henderson 1037d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1038d8e59c4aSRichard Henderson tcg_temp_free_i32(tval); 1039d8e59c4aSRichard Henderson 1040d8e59c4aSRichard Henderson /* Success */ 1041d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1042d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1043d8e59c4aSRichard Henderson 1044d8e59c4aSRichard Henderson /* Failure */ 1045d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1046d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1047d8e59c4aSRichard Henderson 1048d8e59c4aSRichard Henderson gen_set_label(swx_done); 1049d8e59c4aSRichard Henderson 1050d8e59c4aSRichard Henderson /* 1051d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1052d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1053d8e59c4aSRichard Henderson */ 1054d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1055d8e59c4aSRichard Henderson return true; 1056d8e59c4aSRichard Henderson } 1057d8e59c4aSRichard Henderson 105816bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b) 105916bbbbc9SRichard Henderson { 106016bbbbc9SRichard Henderson dc->tb_flags_to_set |= D_FLAG; 106116bbbbc9SRichard Henderson if (type_b && (dc->tb_flags & IMM_FLAG)) { 106216bbbbc9SRichard Henderson dc->tb_flags_to_set |= BIMM_FLAG; 106316bbbbc9SRichard Henderson } 106416bbbbc9SRichard Henderson } 106516bbbbc9SRichard Henderson 106616bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm, 106716bbbbc9SRichard Henderson bool delay, bool abs, int link) 106816bbbbc9SRichard Henderson { 106916bbbbc9SRichard Henderson uint32_t add_pc; 107016bbbbc9SRichard Henderson 107116bbbbc9SRichard Henderson if (delay) { 107216bbbbc9SRichard Henderson setup_dslot(dc, dest_rb < 0); 107316bbbbc9SRichard Henderson } 107416bbbbc9SRichard Henderson 107516bbbbc9SRichard Henderson if (link) { 107616bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next); 107716bbbbc9SRichard Henderson } 107816bbbbc9SRichard Henderson 107916bbbbc9SRichard Henderson /* Store the branch taken destination into btarget. */ 108016bbbbc9SRichard Henderson add_pc = abs ? 0 : dc->base.pc_next; 108116bbbbc9SRichard Henderson if (dest_rb > 0) { 108216bbbbc9SRichard Henderson dc->jmp_dest = -1; 108316bbbbc9SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc); 108416bbbbc9SRichard Henderson } else { 108516bbbbc9SRichard Henderson dc->jmp_dest = add_pc + dest_imm; 108616bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 108716bbbbc9SRichard Henderson } 108816bbbbc9SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 108916bbbbc9SRichard Henderson return true; 109016bbbbc9SRichard Henderson } 109116bbbbc9SRichard Henderson 109216bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \ 109316bbbbc9SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \ 109416bbbbc9SRichard Henderson { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \ 109516bbbbc9SRichard Henderson static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \ 109616bbbbc9SRichard Henderson { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); } 109716bbbbc9SRichard Henderson 109816bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false) 109916bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false) 110016bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false) 110116bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false) 110216bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true) 110316bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true) 110416bbbbc9SRichard Henderson 1105fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm, 1106fd779113SRichard Henderson TCGCond cond, int ra, bool delay) 1107fd779113SRichard Henderson { 1108fd779113SRichard Henderson TCGv_i32 zero, next; 1109fd779113SRichard Henderson 1110fd779113SRichard Henderson if (delay) { 1111fd779113SRichard Henderson setup_dslot(dc, dest_rb < 0); 1112fd779113SRichard Henderson } 1113fd779113SRichard Henderson 1114fd779113SRichard Henderson dc->jmp_cond = cond; 1115fd779113SRichard Henderson 1116fd779113SRichard Henderson /* Cache the condition register in cpu_bvalue across any delay slot. */ 1117fd779113SRichard Henderson tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra)); 1118fd779113SRichard Henderson 1119fd779113SRichard Henderson /* Store the branch taken destination into btarget. */ 1120fd779113SRichard Henderson if (dest_rb > 0) { 1121fd779113SRichard Henderson dc->jmp_dest = -1; 1122fd779113SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next); 1123fd779113SRichard Henderson } else { 1124fd779113SRichard Henderson dc->jmp_dest = dc->base.pc_next + dest_imm; 1125fd779113SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 1126fd779113SRichard Henderson } 1127fd779113SRichard Henderson 1128fd779113SRichard Henderson /* Compute the final destination into btarget. */ 1129fd779113SRichard Henderson zero = tcg_const_i32(0); 1130fd779113SRichard Henderson next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4); 1131fd779113SRichard Henderson tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, 1132fd779113SRichard Henderson reg_for_read(dc, ra), zero, 1133fd779113SRichard Henderson cpu_btarget, next); 1134fd779113SRichard Henderson tcg_temp_free_i32(zero); 1135fd779113SRichard Henderson tcg_temp_free_i32(next); 1136fd779113SRichard Henderson 1137fd779113SRichard Henderson return true; 1138fd779113SRichard Henderson } 1139fd779113SRichard Henderson 1140fd779113SRichard Henderson #define DO_BCC(NAME, COND) \ 1141fd779113SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \ 1142fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \ 1143fd779113SRichard Henderson static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \ 1144fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \ 1145fd779113SRichard Henderson static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \ 1146fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \ 1147fd779113SRichard Henderson static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \ 1148fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); } 1149fd779113SRichard Henderson 1150fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ) 1151fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE) 1152fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT) 1153fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE) 1154fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT) 1155fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE) 1156fd779113SRichard Henderson 1157f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg) 1158f5235314SRichard Henderson { 1159f5235314SRichard Henderson if (trap_userspace(dc, true)) { 1160f5235314SRichard Henderson return true; 1161f5235314SRichard Henderson } 1162f5235314SRichard Henderson tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb)); 1163f5235314SRichard Henderson if (arg->rd) { 1164f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1165f5235314SRichard Henderson } 1166f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP); 1167f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1168f5235314SRichard Henderson 116917e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1170f5235314SRichard Henderson return true; 1171f5235314SRichard Henderson } 1172f5235314SRichard Henderson 1173f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) 1174f5235314SRichard Henderson { 1175f5235314SRichard Henderson uint32_t imm = arg->imm; 1176f5235314SRichard Henderson 1177f5235314SRichard Henderson if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) { 1178f5235314SRichard Henderson return true; 1179f5235314SRichard Henderson } 1180f5235314SRichard Henderson tcg_gen_movi_i32(cpu_pc, imm); 1181f5235314SRichard Henderson if (arg->rd) { 1182f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1183f5235314SRichard Henderson } 1184f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1185f5235314SRichard Henderson 1186f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY 1187f5235314SRichard Henderson switch (imm) { 1188f5235314SRichard Henderson case 0x8: /* syscall trap */ 1189f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_SYSCALL); 1190f5235314SRichard Henderson break; 1191f5235314SRichard Henderson case 0x18: /* debug trap */ 1192f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1193f5235314SRichard Henderson break; 1194f5235314SRichard Henderson default: /* eliminated with trap_userspace check */ 1195f5235314SRichard Henderson g_assert_not_reached(); 1196f5235314SRichard Henderson } 1197f5235314SRichard Henderson #else 1198f5235314SRichard Henderson uint32_t msr_to_set = 0; 1199f5235314SRichard Henderson 1200f5235314SRichard Henderson if (imm != 0x18) { 1201f5235314SRichard Henderson msr_to_set |= MSR_BIP; 1202f5235314SRichard Henderson } 1203f5235314SRichard Henderson if (imm == 0x8 || imm == 0x18) { 1204f5235314SRichard Henderson /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */ 1205f5235314SRichard Henderson msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1; 1206f5235314SRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, 1207f5235314SRichard Henderson ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM)); 1208f5235314SRichard Henderson } 1209f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set); 121017e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1211f5235314SRichard Henderson #endif 1212f5235314SRichard Henderson 1213f5235314SRichard Henderson return true; 1214f5235314SRichard Henderson } 1215f5235314SRichard Henderson 1216ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg) 1217ee8c7f9fSRichard Henderson { 1218ee8c7f9fSRichard Henderson int mbar_imm = arg->imm; 1219ee8c7f9fSRichard Henderson 1220ee8c7f9fSRichard Henderson /* Data access memory barrier. */ 1221ee8c7f9fSRichard Henderson if ((mbar_imm & 2) == 0) { 1222ee8c7f9fSRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 1223ee8c7f9fSRichard Henderson } 1224ee8c7f9fSRichard Henderson 1225ee8c7f9fSRichard Henderson /* Sleep. */ 1226ee8c7f9fSRichard Henderson if (mbar_imm & 16) { 1227ee8c7f9fSRichard Henderson TCGv_i32 tmp_1; 1228ee8c7f9fSRichard Henderson 1229ee8c7f9fSRichard Henderson if (trap_userspace(dc, true)) { 1230ee8c7f9fSRichard Henderson /* Sleep is a privileged instruction. */ 1231ee8c7f9fSRichard Henderson return true; 1232ee8c7f9fSRichard Henderson } 1233ee8c7f9fSRichard Henderson 1234ee8c7f9fSRichard Henderson t_sync_flags(dc); 1235ee8c7f9fSRichard Henderson 1236ee8c7f9fSRichard Henderson tmp_1 = tcg_const_i32(1); 1237ee8c7f9fSRichard Henderson tcg_gen_st_i32(tmp_1, cpu_env, 1238ee8c7f9fSRichard Henderson -offsetof(MicroBlazeCPU, env) 1239ee8c7f9fSRichard Henderson +offsetof(CPUState, halted)); 1240ee8c7f9fSRichard Henderson tcg_temp_free_i32(tmp_1); 1241ee8c7f9fSRichard Henderson 1242ee8c7f9fSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1243ee8c7f9fSRichard Henderson 1244ee8c7f9fSRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1245ee8c7f9fSRichard Henderson } 1246ee8c7f9fSRichard Henderson 1247ee8c7f9fSRichard Henderson /* 1248ee8c7f9fSRichard Henderson * If !(mbar_imm & 1), this is an instruction access memory barrier 1249ee8c7f9fSRichard Henderson * and we need to end the TB so that we recognize self-modified 1250ee8c7f9fSRichard Henderson * code immediately. 1251ee8c7f9fSRichard Henderson * 1252ee8c7f9fSRichard Henderson * However, there are some data mbars that need the TB break 1253ee8c7f9fSRichard Henderson * (and return to main loop) to recognize interrupts right away. 1254ee8c7f9fSRichard Henderson * E.g. recognizing a change to an interrupt controller register. 1255ee8c7f9fSRichard Henderson * 1256ee8c7f9fSRichard Henderson * Therefore, choose to end the TB always. 1257ee8c7f9fSRichard Henderson */ 1258ee8c7f9fSRichard Henderson dc->cpustate_changed = 1; 1259ee8c7f9fSRichard Henderson return true; 1260ee8c7f9fSRichard Henderson } 1261ee8c7f9fSRichard Henderson 1262e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set) 1263e6cb0354SRichard Henderson { 1264e6cb0354SRichard Henderson if (trap_userspace(dc, to_set)) { 1265e6cb0354SRichard Henderson return true; 1266e6cb0354SRichard Henderson } 1267e6cb0354SRichard Henderson dc->tb_flags_to_set |= to_set; 1268e6cb0354SRichard Henderson setup_dslot(dc, true); 1269e6cb0354SRichard Henderson 1270e6cb0354SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 1271e6cb0354SRichard Henderson dc->jmp_dest = -1; 1272e6cb0354SRichard Henderson tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm); 1273e6cb0354SRichard Henderson return true; 1274e6cb0354SRichard Henderson } 1275e6cb0354SRichard Henderson 1276e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \ 1277e6cb0354SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \ 1278e6cb0354SRichard Henderson { return do_rts(dc, arg, IFLAG); } 1279e6cb0354SRichard Henderson 1280e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG) 1281e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG) 1282e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG) 1283e6cb0354SRichard Henderson DO_RTS(rtsd, 0) 1284e6cb0354SRichard Henderson 128520800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 128620800179SRichard Henderson { 128720800179SRichard Henderson /* If opcode_0_illegal, trap. */ 128820800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 128920800179SRichard Henderson trap_illegal(dc, true); 129020800179SRichard Henderson return true; 129120800179SRichard Henderson } 129220800179SRichard Henderson /* 129320800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 129420800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 129520800179SRichard Henderson */ 129620800179SRichard Henderson return false; 1297fcf5ef2aSThomas Huth } 1298fcf5ef2aSThomas Huth 12991074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 1300fcf5ef2aSThomas Huth { 13011074c0fbSRichard Henderson TCGv_i32 t; 13021074c0fbSRichard Henderson 13031074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 13041074c0fbSRichard Henderson t = tcg_temp_new_i32(); 13051074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 13061074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 13071074c0fbSRichard Henderson tcg_temp_free_i32(t); 1308fcf5ef2aSThomas Huth } 1309fcf5ef2aSThomas Huth 13109df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 13111074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 1312fcf5ef2aSThomas Huth { 1313fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 13141074c0fbSRichard Henderson 13151074c0fbSRichard Henderson /* Install MSR_C. */ 13161074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 13171074c0fbSRichard Henderson 13181074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 13191074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 1320fcf5ef2aSThomas Huth } 13219df297a2SRichard Henderson #endif 1322fcf5ef2aSThomas Huth 1323536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) 1324536e340fSRichard Henderson { 1325536e340fSRichard Henderson uint32_t imm = arg->imm; 1326536e340fSRichard Henderson 1327536e340fSRichard Henderson if (trap_userspace(dc, imm != MSR_C)) { 1328536e340fSRichard Henderson return true; 1329536e340fSRichard Henderson } 1330536e340fSRichard Henderson 1331536e340fSRichard Henderson if (arg->rd) { 1332536e340fSRichard Henderson msr_read(dc, cpu_R[arg->rd]); 1333536e340fSRichard Henderson } 1334536e340fSRichard Henderson 1335536e340fSRichard Henderson /* 1336536e340fSRichard Henderson * Handle the carry bit separately. 1337536e340fSRichard Henderson * This is the only bit that userspace can modify. 1338536e340fSRichard Henderson */ 1339536e340fSRichard Henderson if (imm & MSR_C) { 1340536e340fSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, set); 1341536e340fSRichard Henderson } 1342536e340fSRichard Henderson 1343536e340fSRichard Henderson /* 1344536e340fSRichard Henderson * MSR_C and MSR_CC set above. 1345536e340fSRichard Henderson * MSR_PVR is not writable, and is always clear. 1346536e340fSRichard Henderson */ 1347536e340fSRichard Henderson imm &= ~(MSR_C | MSR_CC | MSR_PVR); 1348536e340fSRichard Henderson 1349536e340fSRichard Henderson if (imm != 0) { 1350536e340fSRichard Henderson if (set) { 1351536e340fSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, imm); 1352536e340fSRichard Henderson } else { 1353536e340fSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm); 1354536e340fSRichard Henderson } 1355536e340fSRichard Henderson dc->cpustate_changed = 1; 1356536e340fSRichard Henderson } 1357536e340fSRichard Henderson return true; 1358536e340fSRichard Henderson } 1359536e340fSRichard Henderson 1360536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg) 1361536e340fSRichard Henderson { 1362536e340fSRichard Henderson return do_msrclrset(dc, arg, false); 1363536e340fSRichard Henderson } 1364536e340fSRichard Henderson 1365536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) 1366536e340fSRichard Henderson { 1367536e340fSRichard Henderson return do_msrclrset(dc, arg, true); 1368536e340fSRichard Henderson } 1369536e340fSRichard Henderson 13709df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg) 1371fcf5ef2aSThomas Huth { 13729df297a2SRichard Henderson if (trap_userspace(dc, true)) { 13739df297a2SRichard Henderson return true; 1374f0f7e7f7SEdgar E. Iglesias } 1375f0f7e7f7SEdgar E. Iglesias 13769df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY 13779df297a2SRichard Henderson g_assert_not_reached(); 13789df297a2SRichard Henderson #else 13799df297a2SRichard Henderson if (arg->e && arg->rs != 0x1003) { 13809df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 13819df297a2SRichard Henderson "Invalid extended mts reg 0x%x\n", arg->rs); 13829df297a2SRichard Henderson return true; 13832023e9a3SEdgar E. Iglesias } 1384fcf5ef2aSThomas Huth 13859df297a2SRichard Henderson TCGv_i32 src = reg_for_read(dc, arg->ra); 13869df297a2SRichard Henderson switch (arg->rs) { 1387aa28e6d4SRichard Henderson case SR_MSR: 13889df297a2SRichard Henderson msr_write(dc, src); 1389fcf5ef2aSThomas Huth break; 13909df297a2SRichard Henderson case SR_FSR: 13919df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); 13929df297a2SRichard Henderson break; 13939df297a2SRichard Henderson case 0x800: 13949df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr)); 13959df297a2SRichard Henderson break; 13969df297a2SRichard Henderson case 0x802: 13979df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr)); 13989df297a2SRichard Henderson break; 13999df297a2SRichard Henderson 14009df297a2SRichard Henderson case 0x1000: /* PID */ 14019df297a2SRichard Henderson case 0x1001: /* ZPR */ 14029df297a2SRichard Henderson case 0x1002: /* TLBX */ 14039df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14049df297a2SRichard Henderson case 0x1004: /* TLBHI */ 14059df297a2SRichard Henderson case 0x1005: /* TLBSX */ 14069df297a2SRichard Henderson { 14079df297a2SRichard Henderson TCGv_i32 tmp_ext = tcg_const_i32(arg->e); 14089df297a2SRichard Henderson TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); 14099df297a2SRichard Henderson 14109df297a2SRichard Henderson gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src); 14119df297a2SRichard Henderson tcg_temp_free_i32(tmp_reg); 14129df297a2SRichard Henderson tcg_temp_free_i32(tmp_ext); 14139df297a2SRichard Henderson } 14149df297a2SRichard Henderson break; 14159df297a2SRichard Henderson 14169df297a2SRichard Henderson default: 14179df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs); 14189df297a2SRichard Henderson return true; 14199df297a2SRichard Henderson } 14209df297a2SRichard Henderson dc->cpustate_changed = 1; 14219df297a2SRichard Henderson return true; 14229df297a2SRichard Henderson #endif 14239df297a2SRichard Henderson } 14249df297a2SRichard Henderson 14259df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg) 14269df297a2SRichard Henderson { 14279df297a2SRichard Henderson TCGv_i32 dest = reg_for_write(dc, arg->rd); 14289df297a2SRichard Henderson 14299df297a2SRichard Henderson if (arg->e) { 14309df297a2SRichard Henderson switch (arg->rs) { 1431351527b7SEdgar E. Iglesias case SR_EAR: 1432dbdb77c4SRichard Henderson { 1433dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 14349df297a2SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14359df297a2SRichard Henderson tcg_gen_extrh_i64_i32(dest, t64); 1436dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1437dbdb77c4SRichard Henderson } 14389df297a2SRichard Henderson return true; 14399df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14409df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14419df297a2SRichard Henderson /* Handled below. */ 1442aa28e6d4SRichard Henderson break; 14439df297a2SRichard Henderson #endif 14449df297a2SRichard Henderson case 0x2006 ... 0x2009: 14459df297a2SRichard Henderson /* High bits of PVR6-9 not implemented. */ 14469df297a2SRichard Henderson tcg_gen_movi_i32(dest, 0); 14479df297a2SRichard Henderson return true; 1448fcf5ef2aSThomas Huth default: 14499df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 14509df297a2SRichard Henderson "Invalid extended mfs reg 0x%x\n", arg->rs); 14519df297a2SRichard Henderson return true; 1452fcf5ef2aSThomas Huth } 14539df297a2SRichard Henderson } 14549df297a2SRichard Henderson 14559df297a2SRichard Henderson switch (arg->rs) { 1456aa28e6d4SRichard Henderson case SR_PC: 14579df297a2SRichard Henderson tcg_gen_movi_i32(dest, dc->base.pc_next); 1458fcf5ef2aSThomas Huth break; 1459aa28e6d4SRichard Henderson case SR_MSR: 14609df297a2SRichard Henderson msr_read(dc, dest); 1461fcf5ef2aSThomas Huth break; 1462351527b7SEdgar E. Iglesias case SR_EAR: 1463dbdb77c4SRichard Henderson { 1464dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1465dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14669df297a2SRichard Henderson tcg_gen_extrl_i64_i32(dest, t64); 1467dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1468a1b48e3aSEdgar E. Iglesias } 1469aa28e6d4SRichard Henderson break; 1470351527b7SEdgar E. Iglesias case SR_ESR: 14719df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr)); 1472aa28e6d4SRichard Henderson break; 1473351527b7SEdgar E. Iglesias case SR_FSR: 14749df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr)); 1475aa28e6d4SRichard Henderson break; 1476351527b7SEdgar E. Iglesias case SR_BTR: 14779df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr)); 1478aa28e6d4SRichard Henderson break; 14797cdae31dSTong Ho case SR_EDR: 14809df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr)); 1481fcf5ef2aSThomas Huth break; 1482fcf5ef2aSThomas Huth case 0x800: 14839df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr)); 1484fcf5ef2aSThomas Huth break; 1485fcf5ef2aSThomas Huth case 0x802: 14869df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr)); 1487fcf5ef2aSThomas Huth break; 14889df297a2SRichard Henderson 14899df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14909df297a2SRichard Henderson case 0x1000: /* PID */ 14919df297a2SRichard Henderson case 0x1001: /* ZPR */ 14929df297a2SRichard Henderson case 0x1002: /* TLBX */ 14939df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14949df297a2SRichard Henderson case 0x1004: /* TLBHI */ 14959df297a2SRichard Henderson case 0x1005: /* TLBSX */ 14969df297a2SRichard Henderson { 14979df297a2SRichard Henderson TCGv_i32 tmp_ext = tcg_const_i32(arg->e); 14989df297a2SRichard Henderson TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); 14999df297a2SRichard Henderson 15009df297a2SRichard Henderson gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg); 15019df297a2SRichard Henderson tcg_temp_free_i32(tmp_reg); 15029df297a2SRichard Henderson tcg_temp_free_i32(tmp_ext); 15039df297a2SRichard Henderson } 15049df297a2SRichard Henderson break; 15059df297a2SRichard Henderson #endif 15069df297a2SRichard Henderson 1507351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 15089df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, 15099df297a2SRichard Henderson offsetof(CPUMBState, pvr.regs[arg->rs - 0x2000])); 1510fcf5ef2aSThomas Huth break; 1511fcf5ef2aSThomas Huth default: 15129df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs); 1513fcf5ef2aSThomas Huth break; 1514fcf5ef2aSThomas Huth } 15159df297a2SRichard Henderson return true; 1516fcf5ef2aSThomas Huth } 1517fcf5ef2aSThomas Huth 15183fb394fdSRichard Henderson static void do_rti(DisasContext *dc) 1519fcf5ef2aSThomas Huth { 15203fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1521fcf5ef2aSThomas Huth 15223fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15233fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE); 15243fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM); 15253fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM)); 15263fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 15273fb394fdSRichard Henderson 15283fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1529fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1530fcf5ef2aSThomas Huth } 1531fcf5ef2aSThomas Huth 15323fb394fdSRichard Henderson static void do_rtb(DisasContext *dc) 1533fcf5ef2aSThomas Huth { 15343fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1535fcf5ef2aSThomas Huth 15363fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15373fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP)); 15383fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15393fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 15403fb394fdSRichard Henderson 15413fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1542fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1543fcf5ef2aSThomas Huth } 1544fcf5ef2aSThomas Huth 15453fb394fdSRichard Henderson static void do_rte(DisasContext *dc) 1546fcf5ef2aSThomas Huth { 15473fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1548fcf5ef2aSThomas Huth 15493fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15503fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE); 15513fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15523fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP)); 15533fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1554fcf5ef2aSThomas Huth 15553fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1556fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1557fcf5ef2aSThomas Huth } 1558fcf5ef2aSThomas Huth 1559fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 156052065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl) 1561fcf5ef2aSThomas Huth { 1562fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1563fcf5ef2aSThomas Huth 1564bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 156552065d8fSRichard Henderson return true; 1566fcf5ef2aSThomas Huth } 1567fcf5ef2aSThomas Huth 1568cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 156952065d8fSRichard Henderson if (rb) { 157052065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 1571fcf5ef2aSThomas Huth } else { 157252065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 1573fcf5ef2aSThomas Huth } 1574fcf5ef2aSThomas Huth 1575cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 157652065d8fSRichard Henderson gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl); 1577cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1578cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 157952065d8fSRichard Henderson return true; 158052065d8fSRichard Henderson } 158152065d8fSRichard Henderson 158252065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg) 158352065d8fSRichard Henderson { 158452065d8fSRichard Henderson return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl); 158552065d8fSRichard Henderson } 158652065d8fSRichard Henderson 158752065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg) 158852065d8fSRichard Henderson { 158952065d8fSRichard Henderson return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl); 159052065d8fSRichard Henderson } 159152065d8fSRichard Henderson 159252065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl) 159352065d8fSRichard Henderson { 159452065d8fSRichard Henderson TCGv_i32 t_id, t_ctrl; 159552065d8fSRichard Henderson 159652065d8fSRichard Henderson if (trap_userspace(dc, true)) { 159752065d8fSRichard Henderson return true; 159852065d8fSRichard Henderson } 159952065d8fSRichard Henderson 160052065d8fSRichard Henderson t_id = tcg_temp_new_i32(); 160152065d8fSRichard Henderson if (rb) { 160252065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 160352065d8fSRichard Henderson } else { 160452065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 160552065d8fSRichard Henderson } 160652065d8fSRichard Henderson 160752065d8fSRichard Henderson t_ctrl = tcg_const_i32(ctrl); 160852065d8fSRichard Henderson gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra)); 160952065d8fSRichard Henderson tcg_temp_free_i32(t_id); 161052065d8fSRichard Henderson tcg_temp_free_i32(t_ctrl); 161152065d8fSRichard Henderson return true; 161252065d8fSRichard Henderson } 161352065d8fSRichard Henderson 161452065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg) 161552065d8fSRichard Henderson { 161652065d8fSRichard Henderson return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl); 161752065d8fSRichard Henderson } 161852065d8fSRichard Henderson 161952065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg) 162052065d8fSRichard Henderson { 162152065d8fSRichard Henderson return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); 1622fcf5ef2aSThomas Huth } 1623fcf5ef2aSThomas Huth 1624372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1625fcf5ef2aSThomas Huth { 1626372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1627372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1628372122e3SRichard Henderson int bound; 1629fcf5ef2aSThomas Huth 1630fcf5ef2aSThomas Huth dc->cpu = cpu; 1631683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags; 1632fcf5ef2aSThomas Huth dc->cpustate_changed = 0; 1633d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 163420800179SRichard Henderson dc->r0 = NULL; 163520800179SRichard Henderson dc->r0_set = false; 1636287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 1637b9c58aabSRichard Henderson dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; 1638b9c58aabSRichard Henderson dc->jmp_dest = -1; 1639fcf5ef2aSThomas Huth 1640372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1641372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1642fcf5ef2aSThomas Huth } 1643fcf5ef2aSThomas Huth 1644372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1645fcf5ef2aSThomas Huth { 1646fcf5ef2aSThomas Huth } 1647fcf5ef2aSThomas Huth 1648372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1649372122e3SRichard Henderson { 1650683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1651683a247eSRichard Henderson 1652683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); 1653683a247eSRichard Henderson dc->insn_start = tcg_last_op(); 1654372122e3SRichard Henderson } 1655fcf5ef2aSThomas Huth 1656372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1657372122e3SRichard Henderson const CPUBreakpoint *bp) 1658372122e3SRichard Henderson { 1659372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1660372122e3SRichard Henderson 1661372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1662372122e3SRichard Henderson 1663372122e3SRichard Henderson /* 1664372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1665372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1666372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1667372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1668372122e3SRichard Henderson */ 1669372122e3SRichard Henderson dc->base.pc_next += 4; 1670372122e3SRichard Henderson return true; 1671372122e3SRichard Henderson } 1672372122e3SRichard Henderson 1673372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1674372122e3SRichard Henderson { 1675372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1676372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 167744d1432bSRichard Henderson uint32_t ir; 1678372122e3SRichard Henderson 1679372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1680372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1681372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1682372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1683fcf5ef2aSThomas Huth } 1684fcf5ef2aSThomas Huth 16856f9642d7SRichard Henderson dc->tb_flags_to_set = 0; 16866f9642d7SRichard Henderson 168744d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 168844d1432bSRichard Henderson if (!decode(dc, ir)) { 1689921afa9dSRichard Henderson trap_illegal(dc, true); 169044d1432bSRichard Henderson } 169120800179SRichard Henderson 169220800179SRichard Henderson if (dc->r0) { 169320800179SRichard Henderson tcg_temp_free_i32(dc->r0); 169420800179SRichard Henderson dc->r0 = NULL; 169520800179SRichard Henderson dc->r0_set = false; 169620800179SRichard Henderson } 169720800179SRichard Henderson 16986f9642d7SRichard Henderson /* Discard the imm global when its contents cannot be used. */ 16996f9642d7SRichard Henderson if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { 1700d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1701372122e3SRichard Henderson } 17026f9642d7SRichard Henderson 17031e521ce3SRichard Henderson dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG); 17046f9642d7SRichard Henderson dc->tb_flags |= dc->tb_flags_to_set; 1705d4705ae0SRichard Henderson dc->base.pc_next += 4; 1706fcf5ef2aSThomas Huth 1707b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { 1708372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 1709fcf5ef2aSThomas Huth do_rti(dc); 1710b9c58aabSRichard Henderson } else if (dc->tb_flags & DRTB_FLAG) { 1711fcf5ef2aSThomas Huth do_rtb(dc); 1712b9c58aabSRichard Henderson } else if (dc->tb_flags & DRTE_FLAG) { 1713fcf5ef2aSThomas Huth do_rte(dc); 1714372122e3SRichard Henderson } 1715372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1716372122e3SRichard Henderson } 1717372122e3SRichard Henderson 1718372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1719372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1720*f6278ca9SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1721372122e3SRichard Henderson } 1722372122e3SRichard Henderson } 1723372122e3SRichard Henderson 1724372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1725372122e3SRichard Henderson { 1726372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1727372122e3SRichard Henderson 1728372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1729372122e3SRichard Henderson /* We have already exited the TB. */ 1730372122e3SRichard Henderson return; 1731372122e3SRichard Henderson } 1732372122e3SRichard Henderson 1733372122e3SRichard Henderson t_sync_flags(dc); 1734372122e3SRichard Henderson 1735372122e3SRichard Henderson switch (dc->base.is_jmp) { 1736372122e3SRichard Henderson case DISAS_TOO_MANY: 1737372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1738372122e3SRichard Henderson return; 1739372122e3SRichard Henderson 174017e77796SRichard Henderson case DISAS_EXIT: 1741*f6278ca9SRichard Henderson break; 1742*f6278ca9SRichard Henderson case DISAS_EXIT_NEXT: 1743*f6278ca9SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1744*f6278ca9SRichard Henderson break; 1745*f6278ca9SRichard Henderson case DISAS_EXIT_JUMP: 1746*f6278ca9SRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1747*f6278ca9SRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1748*f6278ca9SRichard Henderson break; 1749372122e3SRichard Henderson 1750372122e3SRichard Henderson case DISAS_JUMP: 1751b9c58aabSRichard Henderson if (dc->jmp_dest != -1 && !cs->singlestep_enabled) { 1752b9c58aabSRichard Henderson /* Direct jump. */ 1753b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1754b9c58aabSRichard Henderson 1755b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_ALWAYS) { 1756b9c58aabSRichard Henderson /* Conditional direct jump. */ 1757b9c58aabSRichard Henderson TCGLabel *taken = gen_new_label(); 1758b9c58aabSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1759b9c58aabSRichard Henderson 1760b9c58aabSRichard Henderson /* 1761b9c58aabSRichard Henderson * Copy bvalue to a temp now, so we can discard bvalue. 1762b9c58aabSRichard Henderson * This can avoid writing bvalue to memory when the 1763b9c58aabSRichard Henderson * delay slot cannot raise an exception. 1764b9c58aabSRichard Henderson */ 1765b9c58aabSRichard Henderson tcg_gen_mov_i32(tmp, cpu_bvalue); 1766b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_bvalue); 1767b9c58aabSRichard Henderson 1768b9c58aabSRichard Henderson tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken); 1769b9c58aabSRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1770b9c58aabSRichard Henderson gen_set_label(taken); 1771b9c58aabSRichard Henderson } 1772b9c58aabSRichard Henderson gen_goto_tb(dc, 0, dc->jmp_dest); 1773b9c58aabSRichard Henderson return; 1774b9c58aabSRichard Henderson } 1775b9c58aabSRichard Henderson 1776b9c58aabSRichard Henderson /* Indirect jump (or direct jump w/ singlestep) */ 1777b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1778b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1779372122e3SRichard Henderson 1780372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1781372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1782372122e3SRichard Henderson } else { 1783372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1784372122e3SRichard Henderson } 1785372122e3SRichard Henderson return; 1786372122e3SRichard Henderson 1787a2b80dbdSRichard Henderson default: 1788a2b80dbdSRichard Henderson g_assert_not_reached(); 1789fcf5ef2aSThomas Huth } 1790*f6278ca9SRichard Henderson 1791*f6278ca9SRichard Henderson /* Finish DISAS_EXIT_* */ 1792*f6278ca9SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1793*f6278ca9SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1794*f6278ca9SRichard Henderson } else { 1795*f6278ca9SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1796*f6278ca9SRichard Henderson } 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; 18250c3da918SRichard Henderson uint32_t iflags; 1826fcf5ef2aSThomas Huth int i; 1827fcf5ef2aSThomas Huth 18280c3da918SRichard Henderson qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n", 18290c3da918SRichard Henderson env->pc, env->msr, 18302e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18312e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18322e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18332e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18340c3da918SRichard Henderson 18350c3da918SRichard Henderson iflags = env->iflags; 18360c3da918SRichard Henderson qemu_fprintf(f, "iflags: 0x%08x", iflags); 18370c3da918SRichard Henderson if (iflags & IMM_FLAG) { 18380c3da918SRichard Henderson qemu_fprintf(f, " IMM(0x%08x)", env->imm); 18392ead1b18SJoe Komlodi } 18400c3da918SRichard Henderson if (iflags & BIMM_FLAG) { 18410c3da918SRichard Henderson qemu_fprintf(f, " BIMM"); 18420c3da918SRichard Henderson } 18430c3da918SRichard Henderson if (iflags & D_FLAG) { 1844b9c58aabSRichard Henderson qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget); 18450c3da918SRichard Henderson } 18460c3da918SRichard Henderson if (iflags & DRTI_FLAG) { 18470c3da918SRichard Henderson qemu_fprintf(f, " DRTI"); 18480c3da918SRichard Henderson } 18490c3da918SRichard Henderson if (iflags & DRTE_FLAG) { 18500c3da918SRichard Henderson qemu_fprintf(f, " DRTE"); 18510c3da918SRichard Henderson } 18520c3da918SRichard Henderson if (iflags & DRTB_FLAG) { 18530c3da918SRichard Henderson qemu_fprintf(f, " DRTB"); 18540c3da918SRichard Henderson } 18550c3da918SRichard Henderson if (iflags & ESR_ESS_FLAG) { 18560c3da918SRichard Henderson qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK); 18572ead1b18SJoe Komlodi } 1858fcf5ef2aSThomas Huth 18590c3da918SRichard Henderson qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" 186019f27b6cSRichard Henderson "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n", 18610c3da918SRichard Henderson env->esr, env->fsr, env->btr, env->edr, 18620c3da918SRichard Henderson env->ear, env->slr, env->shr); 18630c3da918SRichard Henderson 18640c3da918SRichard Henderson for (i = 0; i < 12; i++) { 18650c3da918SRichard Henderson qemu_fprintf(f, "rpvr%-2d=%08x%c", 18660c3da918SRichard Henderson i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' '); 1867fcf5ef2aSThomas Huth } 18680c3da918SRichard Henderson 18690c3da918SRichard Henderson for (i = 0; i < 32; i++) { 18700c3da918SRichard Henderson qemu_fprintf(f, "r%2.2d=%08x%c", 18710c3da918SRichard Henderson i, env->regs[i], i % 4 == 3 ? '\n' : ' '); 18720c3da918SRichard Henderson } 18730c3da918SRichard Henderson qemu_fprintf(f, "\n"); 1874fcf5ef2aSThomas Huth } 1875fcf5ef2aSThomas Huth 1876fcf5ef2aSThomas Huth void mb_tcg_init(void) 1877fcf5ef2aSThomas Huth { 1878480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1879480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1880fcf5ef2aSThomas Huth 1881480d29a8SRichard Henderson static const struct { 1882480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1883480d29a8SRichard Henderson } i32s[] = { 1884e47c2231SRichard Henderson /* 1885e47c2231SRichard Henderson * Note that r0 is handled specially in reg_for_read 1886e47c2231SRichard Henderson * and reg_for_write. Nothing should touch cpu_R[0]. 1887e47c2231SRichard Henderson * Leave that element NULL, which will assert quickly 1888e47c2231SRichard Henderson * inside the tcg generator functions. 1889e47c2231SRichard Henderson */ 1890e47c2231SRichard Henderson R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1891480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1892480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1893480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1894480d29a8SRichard Henderson 1895480d29a8SRichard Henderson SP(pc), 1896480d29a8SRichard Henderson SP(msr), 18971074c0fbSRichard Henderson SP(msr_c), 1898480d29a8SRichard Henderson SP(imm), 1899480d29a8SRichard Henderson SP(iflags), 1900b9c58aabSRichard Henderson SP(bvalue), 1901480d29a8SRichard Henderson SP(btarget), 1902480d29a8SRichard Henderson SP(res_val), 1903480d29a8SRichard Henderson }; 1904480d29a8SRichard Henderson 1905480d29a8SRichard Henderson #undef R 1906480d29a8SRichard Henderson #undef SP 1907480d29a8SRichard Henderson 1908480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1909480d29a8SRichard Henderson *i32s[i].var = 1910480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1911fcf5ef2aSThomas Huth } 191276e8187dSRichard Henderson 1913480d29a8SRichard Henderson cpu_res_addr = 1914480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1915fcf5ef2aSThomas Huth } 1916fcf5ef2aSThomas Huth 1917fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1918fcf5ef2aSThomas Huth target_ulong *data) 1919fcf5ef2aSThomas Huth { 192076e8187dSRichard Henderson env->pc = data[0]; 1921683a247eSRichard Henderson env->iflags = data[1]; 1922fcf5ef2aSThomas Huth } 1923