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 10*ee452036SChetan Pant * version 2.1 of the License, or (at your option) any later version. 11fcf5ef2aSThomas Huth * 12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fcf5ef2aSThomas Huth * Lesser General Public License for more details. 16fcf5ef2aSThomas Huth * 17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fcf5ef2aSThomas Huth */ 20fcf5ef2aSThomas Huth 21fcf5ef2aSThomas Huth #include "qemu/osdep.h" 22fcf5ef2aSThomas Huth #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 42f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */ 43f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2 44f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */ 45f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3 46f6278ca9SRichard 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; 634b893631SRichard Henderson const MicroBlazeCPUConfig *cfg; 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; 73683a247eSRichard Henderson unsigned int tb_flags; 746f9642d7SRichard Henderson unsigned int tb_flags_to_set; 75287b1defSRichard Henderson int mem_index; 76fcf5ef2aSThomas Huth 77b9c58aabSRichard Henderson /* Condition under which to jump, including NEVER and ALWAYS. */ 78b9c58aabSRichard Henderson TCGCond jmp_cond; 79b9c58aabSRichard Henderson 80b9c58aabSRichard Henderson /* Immediate branch-taken destination, or -1 for indirect. */ 81b9c58aabSRichard Henderson uint32_t jmp_dest; 82fcf5ef2aSThomas Huth } DisasContext; 83fcf5ef2aSThomas Huth 8420800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8520800179SRichard Henderson { 8620800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 8720800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 8820800179SRichard Henderson } 8920800179SRichard Henderson return x; 9020800179SRichard Henderson } 9120800179SRichard Henderson 9244d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9344d1432bSRichard Henderson #include "decode-insns.c.inc" 9444d1432bSRichard Henderson 95683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc) 96fcf5ef2aSThomas Huth { 97fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 9888e74b61SRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) { 9988e74b61SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK); 100fcf5ef2aSThomas Huth } 101fcf5ef2aSThomas Huth } 102fcf5ef2aSThomas Huth 10341ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 104fcf5ef2aSThomas Huth { 105fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 106fcf5ef2aSThomas Huth 107fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 108fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 109d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 110fcf5ef2aSThomas Huth } 111fcf5ef2aSThomas Huth 11241ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11341ba37c4SRichard Henderson { 11441ba37c4SRichard Henderson t_sync_flags(dc); 115d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 11641ba37c4SRichard Henderson gen_raise_exception(dc, index); 11741ba37c4SRichard Henderson } 11841ba37c4SRichard Henderson 11941ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12041ba37c4SRichard Henderson { 12141ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12241ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12341ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12441ba37c4SRichard Henderson 12541ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 12641ba37c4SRichard Henderson } 12741ba37c4SRichard Henderson 128fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 129fcf5ef2aSThomas Huth { 130fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 131d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 132fcf5ef2aSThomas Huth #else 133fcf5ef2aSThomas Huth return true; 134fcf5ef2aSThomas Huth #endif 135fcf5ef2aSThomas Huth } 136fcf5ef2aSThomas Huth 137fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 138fcf5ef2aSThomas Huth { 139d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1400b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1410b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1420b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1430b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1440b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 145fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1460f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 147d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 148fcf5ef2aSThomas Huth } else { 1490f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1504059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr(); 151fcf5ef2aSThomas Huth } 152d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 153fcf5ef2aSThomas Huth } 154fcf5ef2aSThomas Huth 155bdfc1e88SEdgar E. Iglesias /* 1569ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1579ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1589ba8cd45SEdgar E. Iglesias */ 1599ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1609ba8cd45SEdgar E. Iglesias { 1612c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE) 1624b893631SRichard Henderson && dc->cfg->illegal_opcode_exception) { 16341ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1649ba8cd45SEdgar E. Iglesias } 1659ba8cd45SEdgar E. Iglesias return cond; 1669ba8cd45SEdgar E. Iglesias } 1679ba8cd45SEdgar E. Iglesias 1689ba8cd45SEdgar E. Iglesias /* 169bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 170bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 171bdfc1e88SEdgar E. Iglesias */ 172bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 173bdfc1e88SEdgar E. Iglesias { 174287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX; 175bdfc1e88SEdgar E. Iglesias 1762c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) { 17741ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 178bdfc1e88SEdgar E. Iglesias } 179bdfc1e88SEdgar E. Iglesias return cond_user; 180bdfc1e88SEdgar E. Iglesias } 181bdfc1e88SEdgar E. Iglesias 1822a7567a2SRichard Henderson /* 1832a7567a2SRichard Henderson * Return true, and log an error, if the current insn is 1842a7567a2SRichard Henderson * within a delay slot. 1852a7567a2SRichard Henderson */ 1862a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type) 1872a7567a2SRichard Henderson { 1882a7567a2SRichard Henderson if (dc->tb_flags & D_FLAG) { 1892a7567a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 1902a7567a2SRichard Henderson "Invalid insn in delay slot: %s at %08x\n", 1912a7567a2SRichard Henderson insn_type, (uint32_t)dc->base.pc_next); 1922a7567a2SRichard Henderson return true; 1932a7567a2SRichard Henderson } 1942a7567a2SRichard Henderson return false; 1952a7567a2SRichard Henderson } 1962a7567a2SRichard Henderson 19720800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 198fcf5ef2aSThomas Huth { 19920800179SRichard Henderson if (likely(reg != 0)) { 20020800179SRichard Henderson return cpu_R[reg]; 201fcf5ef2aSThomas Huth } 20220800179SRichard Henderson if (!dc->r0_set) { 20320800179SRichard Henderson if (dc->r0 == NULL) { 20420800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 205fcf5ef2aSThomas Huth } 20620800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 20720800179SRichard Henderson dc->r0_set = true; 20820800179SRichard Henderson } 20920800179SRichard Henderson return dc->r0; 210fcf5ef2aSThomas Huth } 211fcf5ef2aSThomas Huth 21220800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 21320800179SRichard Henderson { 21420800179SRichard Henderson if (likely(reg != 0)) { 21520800179SRichard Henderson return cpu_R[reg]; 21620800179SRichard Henderson } 21720800179SRichard Henderson if (dc->r0 == NULL) { 21820800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 21920800179SRichard Henderson } 22020800179SRichard Henderson return dc->r0; 221fcf5ef2aSThomas Huth } 222fcf5ef2aSThomas Huth 22320800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 22420800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 22520800179SRichard Henderson { 22620800179SRichard Henderson TCGv_i32 rd, ra, rb; 22720800179SRichard Henderson 22820800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 22920800179SRichard Henderson return true; 230fcf5ef2aSThomas Huth } 23120800179SRichard Henderson 23220800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 23320800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 23420800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 23520800179SRichard Henderson fn(rd, ra, rb); 23620800179SRichard Henderson return true; 23720800179SRichard Henderson } 23820800179SRichard Henderson 23939cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, 24039cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32)) 24139cf3864SRichard Henderson { 24239cf3864SRichard Henderson TCGv_i32 rd, ra; 24339cf3864SRichard Henderson 24439cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) { 24539cf3864SRichard Henderson return true; 24639cf3864SRichard Henderson } 24739cf3864SRichard Henderson 24839cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd); 24939cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra); 25039cf3864SRichard Henderson fn(rd, ra); 25139cf3864SRichard Henderson return true; 25239cf3864SRichard Henderson } 25339cf3864SRichard Henderson 25420800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 25520800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 25620800179SRichard Henderson { 25720800179SRichard Henderson TCGv_i32 rd, ra; 25820800179SRichard Henderson 25920800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 26020800179SRichard Henderson return true; 26120800179SRichard Henderson } 26220800179SRichard Henderson 26320800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 26420800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 26520800179SRichard Henderson fni(rd, ra, arg->imm); 26620800179SRichard Henderson return true; 26720800179SRichard Henderson } 26820800179SRichard Henderson 26920800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 27020800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 27120800179SRichard Henderson { 27220800179SRichard Henderson TCGv_i32 rd, ra, imm; 27320800179SRichard Henderson 27420800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 27520800179SRichard Henderson return true; 27620800179SRichard Henderson } 27720800179SRichard Henderson 27820800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 27920800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 28020800179SRichard Henderson imm = tcg_const_i32(arg->imm); 28120800179SRichard Henderson 28220800179SRichard Henderson fn(rd, ra, imm); 28320800179SRichard Henderson 28420800179SRichard Henderson tcg_temp_free_i32(imm); 28520800179SRichard Henderson return true; 28620800179SRichard Henderson } 28720800179SRichard Henderson 28820800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 28920800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 29020800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 29120800179SRichard Henderson 292607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 293607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 2944b893631SRichard Henderson { return dc->cfg->CFG && do_typea(dc, a, SE, FN); } 295607f5767SRichard Henderson 29639cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 29739cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 29839cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 29939cf3864SRichard Henderson 30039cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 30139cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 3024b893631SRichard Henderson { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); } 30339cf3864SRichard Henderson 30420800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 30520800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 30620800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 30720800179SRichard Henderson 30897955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 30997955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 3104b893631SRichard Henderson { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); } 31197955cebSRichard Henderson 31220800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 31320800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 31420800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 31520800179SRichard Henderson 316d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 317d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 318d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 319d5aead3dSRichard Henderson 320d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 321d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 322d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 323d5aead3dSRichard Henderson 32420800179SRichard Henderson /* No input carry, but output carry. */ 32520800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 32620800179SRichard Henderson { 32720800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 32820800179SRichard Henderson 32920800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 33020800179SRichard Henderson 33120800179SRichard Henderson tcg_temp_free_i32(zero); 33220800179SRichard Henderson } 33320800179SRichard Henderson 33420800179SRichard Henderson /* Input and output carry. */ 33520800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 33620800179SRichard Henderson { 33720800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 33820800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 33920800179SRichard Henderson 34020800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 34120800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 34220800179SRichard Henderson 34320800179SRichard Henderson tcg_temp_free_i32(tmp); 34420800179SRichard Henderson tcg_temp_free_i32(zero); 34520800179SRichard Henderson } 34620800179SRichard Henderson 34720800179SRichard Henderson /* Input carry, but no output carry. */ 34820800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 34920800179SRichard Henderson { 35020800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 35120800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 35220800179SRichard Henderson } 35320800179SRichard Henderson 35420800179SRichard Henderson DO_TYPEA(add, true, gen_add) 35520800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 35620800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 35720800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 35820800179SRichard Henderson 35920800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 36020800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 36120800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 36220800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 36320800179SRichard Henderson 364cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 365cb0a0a4cSRichard Henderson { 366cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 367cb0a0a4cSRichard Henderson } 368cb0a0a4cSRichard Henderson 369cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 370cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 371cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 372cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 373cb0a0a4cSRichard Henderson 374081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 375081d8e02SRichard Henderson { 376081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 377081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 378081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 379081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 380081d8e02SRichard Henderson } 381081d8e02SRichard Henderson 382081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 383081d8e02SRichard Henderson { 384081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 385081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 386081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 387081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 388081d8e02SRichard Henderson } 389081d8e02SRichard Henderson 390081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 391081d8e02SRichard Henderson { 392081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 393081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 394081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 395081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 396081d8e02SRichard Henderson } 397081d8e02SRichard Henderson 398081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 399081d8e02SRichard Henderson { 400081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 401081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 402081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 403081d8e02SRichard Henderson 404081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 405081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 406081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 407081d8e02SRichard Henderson imm_w, imm_s); 408081d8e02SRichard Henderson } else { 409081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 410081d8e02SRichard Henderson } 411081d8e02SRichard Henderson } 412081d8e02SRichard Henderson 413081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 414081d8e02SRichard Henderson { 415081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 416081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 417081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 418081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 419081d8e02SRichard Henderson 420081d8e02SRichard Henderson if (imm_w < imm_s) { 421081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 422081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 423081d8e02SRichard Henderson imm_w, imm_s); 424081d8e02SRichard Henderson } else { 425081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 426081d8e02SRichard Henderson } 427081d8e02SRichard Henderson } 428081d8e02SRichard Henderson 429081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 430081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 431081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 432081d8e02SRichard Henderson 433081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 434081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 435081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 436081d8e02SRichard Henderson 437081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 438081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 439081d8e02SRichard Henderson 44039cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 44139cf3864SRichard Henderson { 44239cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 44339cf3864SRichard Henderson } 44439cf3864SRichard Henderson 44539cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 44639cf3864SRichard Henderson 44758b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 44858b48b63SRichard Henderson { 44958b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 45058b48b63SRichard Henderson 45158b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 45258b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 45358b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 45458b48b63SRichard Henderson tcg_temp_free_i32(lt); 45558b48b63SRichard Henderson } 45658b48b63SRichard Henderson 45758b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 45858b48b63SRichard Henderson { 45958b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 46058b48b63SRichard Henderson 46158b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 46258b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 46358b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 46458b48b63SRichard Henderson tcg_temp_free_i32(lt); 46558b48b63SRichard Henderson } 46658b48b63SRichard Henderson 46758b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 46858b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 469a2b0b90eSRichard Henderson 470d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 471d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 472d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 473d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 474d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 475d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 476d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 477d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 478d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 479d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 480d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 481d5aead3dSRichard Henderson 482d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 483d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 484d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 485d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 486d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 487d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 488d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 489d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 490d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 491d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 492d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 493d5aead3dSRichard Henderson 494d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 495d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 496d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 497d5aead3dSRichard Henderson 498d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 499d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 500d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 501d5aead3dSRichard Henderson 502d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 503b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 504b1354342SRichard Henderson { 505b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 506b1354342SRichard Henderson } 507b1354342SRichard Henderson 508b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 509b1354342SRichard Henderson { 510b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 511b1354342SRichard Henderson } 512b1354342SRichard Henderson 513b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 514b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 515b1354342SRichard Henderson 516e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 517e64b2e5cSRichard Henderson { 5182a7567a2SRichard Henderson if (invalid_delay_slot(dc, "imm")) { 5192a7567a2SRichard Henderson return true; 5202a7567a2SRichard Henderson } 521e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 522e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 5236f9642d7SRichard Henderson dc->tb_flags_to_set = IMM_FLAG; 524e64b2e5cSRichard Henderson return true; 525e64b2e5cSRichard Henderson } 526e64b2e5cSRichard Henderson 52797955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 52897955cebSRichard Henderson { 52997955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 53097955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 53197955cebSRichard Henderson tcg_temp_free_i32(tmp); 53297955cebSRichard Henderson } 53397955cebSRichard Henderson 53497955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 53597955cebSRichard Henderson { 53697955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 53797955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 53897955cebSRichard Henderson tcg_temp_free_i32(tmp); 53997955cebSRichard Henderson } 54097955cebSRichard Henderson 54197955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 54297955cebSRichard Henderson { 54397955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 54497955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 54597955cebSRichard Henderson tcg_temp_free_i32(tmp); 54697955cebSRichard Henderson } 54797955cebSRichard Henderson 54897955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 54997955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 55097955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 55197955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 55297955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 55397955cebSRichard Henderson 554cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 555cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 556cb0a0a4cSRichard Henderson 557607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 558607f5767SRichard Henderson { 559607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 560607f5767SRichard Henderson } 561607f5767SRichard Henderson 562607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 563607f5767SRichard Henderson { 564607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 565607f5767SRichard Henderson } 566607f5767SRichard Henderson 567607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 568607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 569607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 570607f5767SRichard Henderson 571a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 572a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 573a2b0b90eSRichard Henderson { 574a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 575a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 576a2b0b90eSRichard Henderson } 577a2b0b90eSRichard Henderson 578a2b0b90eSRichard Henderson /* Input and output carry. */ 579a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 580a2b0b90eSRichard Henderson { 581a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 582a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 583a2b0b90eSRichard Henderson 584a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 585a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 586a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 587a2b0b90eSRichard Henderson 588a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 589a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 590a2b0b90eSRichard Henderson } 591a2b0b90eSRichard Henderson 592a2b0b90eSRichard Henderson /* No input or output carry. */ 593a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 594a2b0b90eSRichard Henderson { 595a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 596a2b0b90eSRichard Henderson } 597a2b0b90eSRichard Henderson 598a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 599a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 600a2b0b90eSRichard Henderson { 601a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 602a2b0b90eSRichard Henderson 603a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 604a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 605a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 606a2b0b90eSRichard Henderson 607a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 608a2b0b90eSRichard Henderson } 609a2b0b90eSRichard Henderson 610a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 611a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 612a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 613a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 614a2b0b90eSRichard Henderson 615a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 616a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 617a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 618a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 619a2b0b90eSRichard Henderson 62039cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 62139cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 62239cf3864SRichard Henderson 62339cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 62439cf3864SRichard Henderson { 62539cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 62639cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 62739cf3864SRichard Henderson } 62839cf3864SRichard Henderson 62939cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 63039cf3864SRichard Henderson { 63139cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 63239cf3864SRichard Henderson 63339cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 63439cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 63539cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 63639cf3864SRichard Henderson 63739cf3864SRichard Henderson tcg_temp_free_i32(tmp); 63839cf3864SRichard Henderson } 63939cf3864SRichard Henderson 64039cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 64139cf3864SRichard Henderson { 64239cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 64339cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 64439cf3864SRichard Henderson } 64539cf3864SRichard Henderson 64639cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 64739cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 64839cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 64939cf3864SRichard Henderson 65039cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 65139cf3864SRichard Henderson { 65239cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 65339cf3864SRichard Henderson } 65439cf3864SRichard Henderson 65539cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 65639cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 65739cf3864SRichard Henderson 65839cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 65939cf3864SRichard Henderson { 66039cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 66139cf3864SRichard Henderson trap_userspace(dc, true); 66239cf3864SRichard Henderson return true; 66339cf3864SRichard Henderson } 66439cf3864SRichard Henderson 665cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 666cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 667cb0a0a4cSRichard Henderson 668d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 669d8e59c4aSRichard Henderson { 670d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 671d8e59c4aSRichard Henderson 672d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 673d8e59c4aSRichard Henderson if (ra && rb) { 674d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 675d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 676d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 677d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 678d8e59c4aSRichard Henderson } else if (ra) { 679d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 680d8e59c4aSRichard Henderson } else if (rb) { 681d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 682d8e59c4aSRichard Henderson } else { 683d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 684d8e59c4aSRichard Henderson } 685d8e59c4aSRichard Henderson 6864b893631SRichard Henderson if ((ra == 1 || rb == 1) && dc->cfg->stackprot) { 687d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 688d8e59c4aSRichard Henderson } 689d8e59c4aSRichard Henderson return ret; 690d8e59c4aSRichard Henderson } 691d8e59c4aSRichard Henderson 692d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 693d8e59c4aSRichard Henderson { 694d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 695d8e59c4aSRichard Henderson 696d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 697d8e59c4aSRichard Henderson if (ra) { 698d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 699d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 700d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 701d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 702d8e59c4aSRichard Henderson } else { 703d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 704d8e59c4aSRichard Henderson } 705d8e59c4aSRichard Henderson 7064b893631SRichard Henderson if (ra == 1 && dc->cfg->stackprot) { 707d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 708d8e59c4aSRichard Henderson } 709d8e59c4aSRichard Henderson return ret; 710d8e59c4aSRichard Henderson } 711d8e59c4aSRichard Henderson 71219f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY 713d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 714d8e59c4aSRichard Henderson { 7154b893631SRichard Henderson int addr_size = dc->cfg->addr_size; 716d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 717d8e59c4aSRichard Henderson 718d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 719d8e59c4aSRichard Henderson if (rb) { 720d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 721d8e59c4aSRichard Henderson } else { 722d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 723d8e59c4aSRichard Henderson } 724d8e59c4aSRichard Henderson } else { 725d8e59c4aSRichard Henderson if (rb) { 726d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 727d8e59c4aSRichard Henderson } else { 728d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 729d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 730d8e59c4aSRichard Henderson } 731d8e59c4aSRichard Henderson if (addr_size < 64) { 732d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 733d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 734d8e59c4aSRichard Henderson } 735d8e59c4aSRichard Henderson } 736d8e59c4aSRichard Henderson return ret; 737d8e59c4aSRichard Henderson } 73819f27b6cSRichard Henderson #endif 739d8e59c4aSRichard Henderson 740ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd, 741ab0c8d0fSRichard Henderson MemOp size, bool store) 742ab0c8d0fSRichard Henderson { 743ab0c8d0fSRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); 744ab0c8d0fSRichard Henderson 745ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG; 746ab0c8d0fSRichard Henderson iflags |= rd << 5; 747ab0c8d0fSRichard Henderson iflags |= store * ESR_S; 748ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W; 749ab0c8d0fSRichard Henderson 750ab0c8d0fSRichard Henderson tcg_set_insn_start_param(dc->insn_start, 1, iflags); 751ab0c8d0fSRichard Henderson } 752ab0c8d0fSRichard Henderson 753d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 754d8e59c4aSRichard Henderson int mem_index, bool rev) 755d8e59c4aSRichard Henderson { 756d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 757d8e59c4aSRichard Henderson 758d8e59c4aSRichard Henderson /* 759d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 760d8e59c4aSRichard Henderson * 761d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 762d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 763d8e59c4aSRichard Henderson */ 764d8e59c4aSRichard Henderson if (rev) { 765d8e59c4aSRichard Henderson if (size > MO_8) { 766d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 767d8e59c4aSRichard Henderson } 768d8e59c4aSRichard Henderson if (size < MO_32) { 769d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 770d8e59c4aSRichard Henderson } 771d8e59c4aSRichard Henderson } 772d8e59c4aSRichard Henderson 773ab0c8d0fSRichard Henderson if (size > MO_8 && 774ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 7754b893631SRichard Henderson dc->cfg->unaligned_exceptions) { 776ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false); 777ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 778d8e59c4aSRichard Henderson } 779d8e59c4aSRichard Henderson 780ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); 781d8e59c4aSRichard Henderson 782d8e59c4aSRichard Henderson tcg_temp_free(addr); 783d8e59c4aSRichard Henderson return true; 784d8e59c4aSRichard Henderson } 785d8e59c4aSRichard Henderson 786d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 787d8e59c4aSRichard Henderson { 788d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 789d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 790d8e59c4aSRichard Henderson } 791d8e59c4aSRichard Henderson 792d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 793d8e59c4aSRichard Henderson { 794d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 795d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 796d8e59c4aSRichard Henderson } 797d8e59c4aSRichard Henderson 798d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 799d8e59c4aSRichard Henderson { 800d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 801d8e59c4aSRichard Henderson return true; 802d8e59c4aSRichard Henderson } 80319f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 80419f27b6cSRichard Henderson return true; 80519f27b6cSRichard Henderson #else 806d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 807d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 80819f27b6cSRichard Henderson #endif 809d8e59c4aSRichard Henderson } 810d8e59c4aSRichard Henderson 811d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 812d8e59c4aSRichard Henderson { 813d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 814d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 815d8e59c4aSRichard Henderson } 816d8e59c4aSRichard Henderson 817d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 818d8e59c4aSRichard Henderson { 819d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 820d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 821d8e59c4aSRichard Henderson } 822d8e59c4aSRichard Henderson 823d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 824d8e59c4aSRichard Henderson { 825d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 826d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 827d8e59c4aSRichard Henderson } 828d8e59c4aSRichard Henderson 829d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 830d8e59c4aSRichard Henderson { 831d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 832d8e59c4aSRichard Henderson return true; 833d8e59c4aSRichard Henderson } 83419f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 83519f27b6cSRichard Henderson return true; 83619f27b6cSRichard Henderson #else 837d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 838d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 83919f27b6cSRichard Henderson #endif 840d8e59c4aSRichard Henderson } 841d8e59c4aSRichard Henderson 842d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 843d8e59c4aSRichard Henderson { 844d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 845d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 846d8e59c4aSRichard Henderson } 847d8e59c4aSRichard Henderson 848d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 849d8e59c4aSRichard Henderson { 850d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 851d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 852d8e59c4aSRichard Henderson } 853d8e59c4aSRichard Henderson 854d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 855d8e59c4aSRichard Henderson { 856d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 857d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 858d8e59c4aSRichard Henderson } 859d8e59c4aSRichard Henderson 860d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 861d8e59c4aSRichard Henderson { 862d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 863d8e59c4aSRichard Henderson return true; 864d8e59c4aSRichard Henderson } 86519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 86619f27b6cSRichard Henderson return true; 86719f27b6cSRichard Henderson #else 868d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 869d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 87019f27b6cSRichard Henderson #endif 871d8e59c4aSRichard Henderson } 872d8e59c4aSRichard Henderson 873d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg) 874d8e59c4aSRichard Henderson { 875d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 876d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 877d8e59c4aSRichard Henderson } 878d8e59c4aSRichard Henderson 879d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg) 880d8e59c4aSRichard Henderson { 881d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 882d8e59c4aSRichard Henderson 883d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */ 884d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 885d8e59c4aSRichard Henderson 886d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); 887d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 888d8e59c4aSRichard Henderson tcg_temp_free(addr); 889d8e59c4aSRichard Henderson 890d8e59c4aSRichard Henderson if (arg->rd) { 891d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 892d8e59c4aSRichard Henderson } 893d8e59c4aSRichard Henderson 894d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 895d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 896d8e59c4aSRichard Henderson return true; 897d8e59c4aSRichard Henderson } 898d8e59c4aSRichard Henderson 899d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 900d8e59c4aSRichard Henderson int mem_index, bool rev) 901d8e59c4aSRichard Henderson { 902d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 903d8e59c4aSRichard Henderson 904d8e59c4aSRichard Henderson /* 905d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 906d8e59c4aSRichard Henderson * 907d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 908d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 909d8e59c4aSRichard Henderson */ 910d8e59c4aSRichard Henderson if (rev) { 911d8e59c4aSRichard Henderson if (size > MO_8) { 912d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 913d8e59c4aSRichard Henderson } 914d8e59c4aSRichard Henderson if (size < MO_32) { 915d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 916d8e59c4aSRichard Henderson } 917d8e59c4aSRichard Henderson } 918d8e59c4aSRichard Henderson 919ab0c8d0fSRichard Henderson if (size > MO_8 && 920ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 9214b893631SRichard Henderson dc->cfg->unaligned_exceptions) { 922ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true); 923ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 924d8e59c4aSRichard Henderson } 925d8e59c4aSRichard Henderson 926ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 927ab0c8d0fSRichard Henderson 928d8e59c4aSRichard Henderson tcg_temp_free(addr); 929d8e59c4aSRichard Henderson return true; 930d8e59c4aSRichard Henderson } 931d8e59c4aSRichard Henderson 932d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 933d8e59c4aSRichard Henderson { 934d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 935d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 936d8e59c4aSRichard Henderson } 937d8e59c4aSRichard Henderson 938d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 939d8e59c4aSRichard Henderson { 940d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 941d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 942d8e59c4aSRichard Henderson } 943d8e59c4aSRichard Henderson 944d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 945d8e59c4aSRichard Henderson { 946d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 947d8e59c4aSRichard Henderson return true; 948d8e59c4aSRichard Henderson } 94919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 95019f27b6cSRichard Henderson return true; 95119f27b6cSRichard Henderson #else 952d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 953d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 95419f27b6cSRichard Henderson #endif 955d8e59c4aSRichard Henderson } 956d8e59c4aSRichard Henderson 957d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 958d8e59c4aSRichard Henderson { 959d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 960d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 961d8e59c4aSRichard Henderson } 962d8e59c4aSRichard Henderson 963d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg) 964d8e59c4aSRichard Henderson { 965d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 966d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 967d8e59c4aSRichard Henderson } 968d8e59c4aSRichard Henderson 969d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 970d8e59c4aSRichard Henderson { 971d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 972d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 973d8e59c4aSRichard Henderson } 974d8e59c4aSRichard Henderson 975d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 976d8e59c4aSRichard Henderson { 977d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 978d8e59c4aSRichard Henderson return true; 979d8e59c4aSRichard Henderson } 98019f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 98119f27b6cSRichard Henderson return true; 98219f27b6cSRichard Henderson #else 983d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 984d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 98519f27b6cSRichard Henderson #endif 986d8e59c4aSRichard Henderson } 987d8e59c4aSRichard Henderson 988d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 989d8e59c4aSRichard Henderson { 990d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 991d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 992d8e59c4aSRichard Henderson } 993d8e59c4aSRichard Henderson 994d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 995d8e59c4aSRichard Henderson { 996d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 997d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 998d8e59c4aSRichard Henderson } 999d8e59c4aSRichard Henderson 1000d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 1001d8e59c4aSRichard Henderson { 1002d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1003d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 1004d8e59c4aSRichard Henderson } 1005d8e59c4aSRichard Henderson 1006d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 1007d8e59c4aSRichard Henderson { 1008d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 1009d8e59c4aSRichard Henderson return true; 1010d8e59c4aSRichard Henderson } 101119f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 101219f27b6cSRichard Henderson return true; 101319f27b6cSRichard Henderson #else 1014d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 1015d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 101619f27b6cSRichard Henderson #endif 1017d8e59c4aSRichard Henderson } 1018d8e59c4aSRichard Henderson 1019d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 1020d8e59c4aSRichard Henderson { 1021d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 1022d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 1023d8e59c4aSRichard Henderson } 1024d8e59c4aSRichard Henderson 1025d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 1026d8e59c4aSRichard Henderson { 1027d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1028d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 1029d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 1030d8e59c4aSRichard Henderson TCGv_i32 tval; 1031d8e59c4aSRichard Henderson 1032d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 1033d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1034d8e59c4aSRichard Henderson 1035d8e59c4aSRichard Henderson /* 1036d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 1037d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 1038d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 1039d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 1040d8e59c4aSRichard Henderson */ 1041d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 1042d8e59c4aSRichard Henderson tcg_temp_free(addr); 1043d8e59c4aSRichard Henderson 1044d8e59c4aSRichard Henderson /* 1045d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 1046d8e59c4aSRichard Henderson * the reserved location. 1047d8e59c4aSRichard Henderson */ 1048d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1049d8e59c4aSRichard Henderson 1050d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1051d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1052d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1053d8e59c4aSRichard Henderson 1054d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1055d8e59c4aSRichard Henderson tcg_temp_free_i32(tval); 1056d8e59c4aSRichard Henderson 1057d8e59c4aSRichard Henderson /* Success */ 1058d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1059d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1060d8e59c4aSRichard Henderson 1061d8e59c4aSRichard Henderson /* Failure */ 1062d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1063d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1064d8e59c4aSRichard Henderson 1065d8e59c4aSRichard Henderson gen_set_label(swx_done); 1066d8e59c4aSRichard Henderson 1067d8e59c4aSRichard Henderson /* 1068d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1069d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1070d8e59c4aSRichard Henderson */ 1071d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1072d8e59c4aSRichard Henderson return true; 1073d8e59c4aSRichard Henderson } 1074d8e59c4aSRichard Henderson 107516bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b) 107616bbbbc9SRichard Henderson { 107716bbbbc9SRichard Henderson dc->tb_flags_to_set |= D_FLAG; 107816bbbbc9SRichard Henderson if (type_b && (dc->tb_flags & IMM_FLAG)) { 107916bbbbc9SRichard Henderson dc->tb_flags_to_set |= BIMM_FLAG; 108016bbbbc9SRichard Henderson } 108116bbbbc9SRichard Henderson } 108216bbbbc9SRichard Henderson 108316bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm, 108416bbbbc9SRichard Henderson bool delay, bool abs, int link) 108516bbbbc9SRichard Henderson { 108616bbbbc9SRichard Henderson uint32_t add_pc; 108716bbbbc9SRichard Henderson 10882a7567a2SRichard Henderson if (invalid_delay_slot(dc, "branch")) { 10892a7567a2SRichard Henderson return true; 10902a7567a2SRichard Henderson } 109116bbbbc9SRichard Henderson if (delay) { 109216bbbbc9SRichard Henderson setup_dslot(dc, dest_rb < 0); 109316bbbbc9SRichard Henderson } 109416bbbbc9SRichard Henderson 109516bbbbc9SRichard Henderson if (link) { 109616bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next); 109716bbbbc9SRichard Henderson } 109816bbbbc9SRichard Henderson 109916bbbbc9SRichard Henderson /* Store the branch taken destination into btarget. */ 110016bbbbc9SRichard Henderson add_pc = abs ? 0 : dc->base.pc_next; 110116bbbbc9SRichard Henderson if (dest_rb > 0) { 110216bbbbc9SRichard Henderson dc->jmp_dest = -1; 110316bbbbc9SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc); 110416bbbbc9SRichard Henderson } else { 110516bbbbc9SRichard Henderson dc->jmp_dest = add_pc + dest_imm; 110616bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 110716bbbbc9SRichard Henderson } 110816bbbbc9SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 110916bbbbc9SRichard Henderson return true; 111016bbbbc9SRichard Henderson } 111116bbbbc9SRichard Henderson 111216bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \ 111316bbbbc9SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \ 111416bbbbc9SRichard Henderson { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \ 111516bbbbc9SRichard Henderson static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \ 111616bbbbc9SRichard Henderson { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); } 111716bbbbc9SRichard Henderson 111816bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false) 111916bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false) 112016bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false) 112116bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false) 112216bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true) 112316bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true) 112416bbbbc9SRichard Henderson 1125fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm, 1126fd779113SRichard Henderson TCGCond cond, int ra, bool delay) 1127fd779113SRichard Henderson { 1128fd779113SRichard Henderson TCGv_i32 zero, next; 1129fd779113SRichard Henderson 11302a7567a2SRichard Henderson if (invalid_delay_slot(dc, "bcc")) { 11312a7567a2SRichard Henderson return true; 11322a7567a2SRichard Henderson } 1133fd779113SRichard Henderson if (delay) { 1134fd779113SRichard Henderson setup_dslot(dc, dest_rb < 0); 1135fd779113SRichard Henderson } 1136fd779113SRichard Henderson 1137fd779113SRichard Henderson dc->jmp_cond = cond; 1138fd779113SRichard Henderson 1139fd779113SRichard Henderson /* Cache the condition register in cpu_bvalue across any delay slot. */ 1140fd779113SRichard Henderson tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra)); 1141fd779113SRichard Henderson 1142fd779113SRichard Henderson /* Store the branch taken destination into btarget. */ 1143fd779113SRichard Henderson if (dest_rb > 0) { 1144fd779113SRichard Henderson dc->jmp_dest = -1; 1145fd779113SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next); 1146fd779113SRichard Henderson } else { 1147fd779113SRichard Henderson dc->jmp_dest = dc->base.pc_next + dest_imm; 1148fd779113SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 1149fd779113SRichard Henderson } 1150fd779113SRichard Henderson 1151fd779113SRichard Henderson /* Compute the final destination into btarget. */ 1152fd779113SRichard Henderson zero = tcg_const_i32(0); 1153fd779113SRichard Henderson next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4); 1154fd779113SRichard Henderson tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, 1155fd779113SRichard Henderson reg_for_read(dc, ra), zero, 1156fd779113SRichard Henderson cpu_btarget, next); 1157fd779113SRichard Henderson tcg_temp_free_i32(zero); 1158fd779113SRichard Henderson tcg_temp_free_i32(next); 1159fd779113SRichard Henderson 1160fd779113SRichard Henderson return true; 1161fd779113SRichard Henderson } 1162fd779113SRichard Henderson 1163fd779113SRichard Henderson #define DO_BCC(NAME, COND) \ 1164fd779113SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \ 1165fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \ 1166fd779113SRichard Henderson static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \ 1167fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \ 1168fd779113SRichard Henderson static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \ 1169fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \ 1170fd779113SRichard Henderson static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \ 1171fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); } 1172fd779113SRichard Henderson 1173fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ) 1174fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE) 1175fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT) 1176fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE) 1177fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT) 1178fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE) 1179fd779113SRichard Henderson 1180f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg) 1181f5235314SRichard Henderson { 1182f5235314SRichard Henderson if (trap_userspace(dc, true)) { 1183f5235314SRichard Henderson return true; 1184f5235314SRichard Henderson } 11852a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brk")) { 11862a7567a2SRichard Henderson return true; 11872a7567a2SRichard Henderson } 11882a7567a2SRichard Henderson 1189f5235314SRichard Henderson tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb)); 1190f5235314SRichard Henderson if (arg->rd) { 1191f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1192f5235314SRichard Henderson } 1193f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP); 1194f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1195f5235314SRichard Henderson 119617e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1197f5235314SRichard Henderson return true; 1198f5235314SRichard Henderson } 1199f5235314SRichard Henderson 1200f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) 1201f5235314SRichard Henderson { 1202f5235314SRichard Henderson uint32_t imm = arg->imm; 1203f5235314SRichard Henderson 1204f5235314SRichard Henderson if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) { 1205f5235314SRichard Henderson return true; 1206f5235314SRichard Henderson } 12072a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brki")) { 12082a7567a2SRichard Henderson return true; 12092a7567a2SRichard Henderson } 12102a7567a2SRichard Henderson 1211f5235314SRichard Henderson tcg_gen_movi_i32(cpu_pc, imm); 1212f5235314SRichard Henderson if (arg->rd) { 1213f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1214f5235314SRichard Henderson } 1215f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1216f5235314SRichard Henderson 1217f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY 1218f5235314SRichard Henderson switch (imm) { 1219f5235314SRichard Henderson case 0x8: /* syscall trap */ 1220f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_SYSCALL); 1221f5235314SRichard Henderson break; 1222f5235314SRichard Henderson case 0x18: /* debug trap */ 1223f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1224f5235314SRichard Henderson break; 1225f5235314SRichard Henderson default: /* eliminated with trap_userspace check */ 1226f5235314SRichard Henderson g_assert_not_reached(); 1227f5235314SRichard Henderson } 1228f5235314SRichard Henderson #else 1229f5235314SRichard Henderson uint32_t msr_to_set = 0; 1230f5235314SRichard Henderson 1231f5235314SRichard Henderson if (imm != 0x18) { 1232f5235314SRichard Henderson msr_to_set |= MSR_BIP; 1233f5235314SRichard Henderson } 1234f5235314SRichard Henderson if (imm == 0x8 || imm == 0x18) { 1235f5235314SRichard Henderson /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */ 1236f5235314SRichard Henderson msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1; 1237f5235314SRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, 1238f5235314SRichard Henderson ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM)); 1239f5235314SRichard Henderson } 1240f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set); 124117e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1242f5235314SRichard Henderson #endif 1243f5235314SRichard Henderson 1244f5235314SRichard Henderson return true; 1245f5235314SRichard Henderson } 1246f5235314SRichard Henderson 1247ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg) 1248ee8c7f9fSRichard Henderson { 1249ee8c7f9fSRichard Henderson int mbar_imm = arg->imm; 1250ee8c7f9fSRichard Henderson 12512a7567a2SRichard Henderson /* Note that mbar is a specialized branch instruction. */ 12522a7567a2SRichard Henderson if (invalid_delay_slot(dc, "mbar")) { 12532a7567a2SRichard Henderson return true; 12542a7567a2SRichard Henderson } 12552a7567a2SRichard Henderson 1256ee8c7f9fSRichard Henderson /* Data access memory barrier. */ 1257ee8c7f9fSRichard Henderson if ((mbar_imm & 2) == 0) { 1258ee8c7f9fSRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 1259ee8c7f9fSRichard Henderson } 1260ee8c7f9fSRichard Henderson 1261ee8c7f9fSRichard Henderson /* Sleep. */ 1262ee8c7f9fSRichard Henderson if (mbar_imm & 16) { 1263ee8c7f9fSRichard Henderson TCGv_i32 tmp_1; 1264ee8c7f9fSRichard Henderson 1265ee8c7f9fSRichard Henderson if (trap_userspace(dc, true)) { 1266ee8c7f9fSRichard Henderson /* Sleep is a privileged instruction. */ 1267ee8c7f9fSRichard Henderson return true; 1268ee8c7f9fSRichard Henderson } 1269ee8c7f9fSRichard Henderson 1270ee8c7f9fSRichard Henderson t_sync_flags(dc); 1271ee8c7f9fSRichard Henderson 1272ee8c7f9fSRichard Henderson tmp_1 = tcg_const_i32(1); 1273ee8c7f9fSRichard Henderson tcg_gen_st_i32(tmp_1, cpu_env, 1274ee8c7f9fSRichard Henderson -offsetof(MicroBlazeCPU, env) 1275ee8c7f9fSRichard Henderson +offsetof(CPUState, halted)); 1276ee8c7f9fSRichard Henderson tcg_temp_free_i32(tmp_1); 1277ee8c7f9fSRichard Henderson 1278ee8c7f9fSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1279ee8c7f9fSRichard Henderson 1280ee8c7f9fSRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1281ee8c7f9fSRichard Henderson } 1282ee8c7f9fSRichard Henderson 1283ee8c7f9fSRichard Henderson /* 1284ee8c7f9fSRichard Henderson * If !(mbar_imm & 1), this is an instruction access memory barrier 1285ee8c7f9fSRichard Henderson * and we need to end the TB so that we recognize self-modified 1286ee8c7f9fSRichard Henderson * code immediately. 1287ee8c7f9fSRichard Henderson * 1288ee8c7f9fSRichard Henderson * However, there are some data mbars that need the TB break 1289ee8c7f9fSRichard Henderson * (and return to main loop) to recognize interrupts right away. 1290ee8c7f9fSRichard Henderson * E.g. recognizing a change to an interrupt controller register. 1291ee8c7f9fSRichard Henderson * 1292ee8c7f9fSRichard Henderson * Therefore, choose to end the TB always. 1293ee8c7f9fSRichard Henderson */ 129443b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1295ee8c7f9fSRichard Henderson return true; 1296ee8c7f9fSRichard Henderson } 1297ee8c7f9fSRichard Henderson 1298e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set) 1299e6cb0354SRichard Henderson { 1300e6cb0354SRichard Henderson if (trap_userspace(dc, to_set)) { 1301e6cb0354SRichard Henderson return true; 1302e6cb0354SRichard Henderson } 13032a7567a2SRichard Henderson if (invalid_delay_slot(dc, "rts")) { 13042a7567a2SRichard Henderson return true; 13052a7567a2SRichard Henderson } 13062a7567a2SRichard Henderson 1307e6cb0354SRichard Henderson dc->tb_flags_to_set |= to_set; 1308e6cb0354SRichard Henderson setup_dslot(dc, true); 1309e6cb0354SRichard Henderson 1310e6cb0354SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 1311e6cb0354SRichard Henderson dc->jmp_dest = -1; 1312e6cb0354SRichard Henderson tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm); 1313e6cb0354SRichard Henderson return true; 1314e6cb0354SRichard Henderson } 1315e6cb0354SRichard Henderson 1316e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \ 1317e6cb0354SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \ 1318e6cb0354SRichard Henderson { return do_rts(dc, arg, IFLAG); } 1319e6cb0354SRichard Henderson 1320e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG) 1321e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG) 1322e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG) 1323e6cb0354SRichard Henderson DO_RTS(rtsd, 0) 1324e6cb0354SRichard Henderson 132520800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 132620800179SRichard Henderson { 132720800179SRichard Henderson /* If opcode_0_illegal, trap. */ 13284b893631SRichard Henderson if (dc->cfg->opcode_0_illegal) { 132920800179SRichard Henderson trap_illegal(dc, true); 133020800179SRichard Henderson return true; 133120800179SRichard Henderson } 133220800179SRichard Henderson /* 133320800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 133420800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 133520800179SRichard Henderson */ 133620800179SRichard Henderson return false; 1337fcf5ef2aSThomas Huth } 1338fcf5ef2aSThomas Huth 13391074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 1340fcf5ef2aSThomas Huth { 13411074c0fbSRichard Henderson TCGv_i32 t; 13421074c0fbSRichard Henderson 13431074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 13441074c0fbSRichard Henderson t = tcg_temp_new_i32(); 13451074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 13461074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 13471074c0fbSRichard Henderson tcg_temp_free_i32(t); 1348fcf5ef2aSThomas Huth } 1349fcf5ef2aSThomas Huth 1350536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) 1351536e340fSRichard Henderson { 1352536e340fSRichard Henderson uint32_t imm = arg->imm; 1353536e340fSRichard Henderson 1354536e340fSRichard Henderson if (trap_userspace(dc, imm != MSR_C)) { 1355536e340fSRichard Henderson return true; 1356536e340fSRichard Henderson } 1357536e340fSRichard Henderson 1358536e340fSRichard Henderson if (arg->rd) { 1359536e340fSRichard Henderson msr_read(dc, cpu_R[arg->rd]); 1360536e340fSRichard Henderson } 1361536e340fSRichard Henderson 1362536e340fSRichard Henderson /* 1363536e340fSRichard Henderson * Handle the carry bit separately. 1364536e340fSRichard Henderson * This is the only bit that userspace can modify. 1365536e340fSRichard Henderson */ 1366536e340fSRichard Henderson if (imm & MSR_C) { 1367536e340fSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, set); 1368536e340fSRichard Henderson } 1369536e340fSRichard Henderson 1370536e340fSRichard Henderson /* 1371536e340fSRichard Henderson * MSR_C and MSR_CC set above. 1372536e340fSRichard Henderson * MSR_PVR is not writable, and is always clear. 1373536e340fSRichard Henderson */ 1374536e340fSRichard Henderson imm &= ~(MSR_C | MSR_CC | MSR_PVR); 1375536e340fSRichard Henderson 1376536e340fSRichard Henderson if (imm != 0) { 1377536e340fSRichard Henderson if (set) { 1378536e340fSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, imm); 1379536e340fSRichard Henderson } else { 1380536e340fSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm); 1381536e340fSRichard Henderson } 138243b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1383536e340fSRichard Henderson } 1384536e340fSRichard Henderson return true; 1385536e340fSRichard Henderson } 1386536e340fSRichard Henderson 1387536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg) 1388536e340fSRichard Henderson { 1389536e340fSRichard Henderson return do_msrclrset(dc, arg, false); 1390536e340fSRichard Henderson } 1391536e340fSRichard Henderson 1392536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) 1393536e340fSRichard Henderson { 1394536e340fSRichard Henderson return do_msrclrset(dc, arg, true); 1395536e340fSRichard Henderson } 1396536e340fSRichard Henderson 13979df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg) 1398fcf5ef2aSThomas Huth { 13999df297a2SRichard Henderson if (trap_userspace(dc, true)) { 14009df297a2SRichard Henderson return true; 1401f0f7e7f7SEdgar E. Iglesias } 1402f0f7e7f7SEdgar E. Iglesias 14039df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY 14049df297a2SRichard Henderson g_assert_not_reached(); 14059df297a2SRichard Henderson #else 14069df297a2SRichard Henderson if (arg->e && arg->rs != 0x1003) { 14079df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 14089df297a2SRichard Henderson "Invalid extended mts reg 0x%x\n", arg->rs); 14099df297a2SRichard Henderson return true; 14102023e9a3SEdgar E. Iglesias } 1411fcf5ef2aSThomas Huth 14129df297a2SRichard Henderson TCGv_i32 src = reg_for_read(dc, arg->ra); 14139df297a2SRichard Henderson switch (arg->rs) { 1414aa28e6d4SRichard Henderson case SR_MSR: 141543b34134SRichard Henderson /* Install MSR_C. */ 141643b34134SRichard Henderson tcg_gen_extract_i32(cpu_msr_c, src, 2, 1); 141743b34134SRichard Henderson /* 141843b34134SRichard Henderson * Clear MSR_C and MSR_CC; 141943b34134SRichard Henderson * MSR_PVR is not writable, and is always clear. 142043b34134SRichard Henderson */ 142143b34134SRichard Henderson tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR)); 1422fcf5ef2aSThomas Huth break; 14239df297a2SRichard Henderson case SR_FSR: 14249df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); 14259df297a2SRichard Henderson break; 14269df297a2SRichard Henderson case 0x800: 14279df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr)); 14289df297a2SRichard Henderson break; 14299df297a2SRichard Henderson case 0x802: 14309df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr)); 14319df297a2SRichard Henderson break; 14329df297a2SRichard Henderson 14339df297a2SRichard Henderson case 0x1000: /* PID */ 14349df297a2SRichard Henderson case 0x1001: /* ZPR */ 14359df297a2SRichard Henderson case 0x1002: /* TLBX */ 14369df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14379df297a2SRichard Henderson case 0x1004: /* TLBHI */ 14389df297a2SRichard Henderson case 0x1005: /* TLBSX */ 14399df297a2SRichard Henderson { 14409df297a2SRichard Henderson TCGv_i32 tmp_ext = tcg_const_i32(arg->e); 14419df297a2SRichard Henderson TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); 14429df297a2SRichard Henderson 14439df297a2SRichard Henderson gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src); 14449df297a2SRichard Henderson tcg_temp_free_i32(tmp_reg); 14459df297a2SRichard Henderson tcg_temp_free_i32(tmp_ext); 14469df297a2SRichard Henderson } 14479df297a2SRichard Henderson break; 14489df297a2SRichard Henderson 14499df297a2SRichard Henderson default: 14509df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs); 14519df297a2SRichard Henderson return true; 14529df297a2SRichard Henderson } 145343b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 14549df297a2SRichard Henderson return true; 14559df297a2SRichard Henderson #endif 14569df297a2SRichard Henderson } 14579df297a2SRichard Henderson 14589df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg) 14599df297a2SRichard Henderson { 14609df297a2SRichard Henderson TCGv_i32 dest = reg_for_write(dc, arg->rd); 14619df297a2SRichard Henderson 14629df297a2SRichard Henderson if (arg->e) { 14639df297a2SRichard Henderson switch (arg->rs) { 1464351527b7SEdgar E. Iglesias case SR_EAR: 1465dbdb77c4SRichard Henderson { 1466dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 14679df297a2SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14689df297a2SRichard Henderson tcg_gen_extrh_i64_i32(dest, t64); 1469dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1470dbdb77c4SRichard Henderson } 14719df297a2SRichard Henderson return true; 14729df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14739df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14749df297a2SRichard Henderson /* Handled below. */ 1475aa28e6d4SRichard Henderson break; 14769df297a2SRichard Henderson #endif 14779df297a2SRichard Henderson case 0x2006 ... 0x2009: 14789df297a2SRichard Henderson /* High bits of PVR6-9 not implemented. */ 14799df297a2SRichard Henderson tcg_gen_movi_i32(dest, 0); 14809df297a2SRichard Henderson return true; 1481fcf5ef2aSThomas Huth default: 14829df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 14839df297a2SRichard Henderson "Invalid extended mfs reg 0x%x\n", arg->rs); 14849df297a2SRichard Henderson return true; 1485fcf5ef2aSThomas Huth } 14869df297a2SRichard Henderson } 14879df297a2SRichard Henderson 14889df297a2SRichard Henderson switch (arg->rs) { 1489aa28e6d4SRichard Henderson case SR_PC: 14909df297a2SRichard Henderson tcg_gen_movi_i32(dest, dc->base.pc_next); 1491fcf5ef2aSThomas Huth break; 1492aa28e6d4SRichard Henderson case SR_MSR: 14939df297a2SRichard Henderson msr_read(dc, dest); 1494fcf5ef2aSThomas Huth break; 1495351527b7SEdgar E. Iglesias case SR_EAR: 1496dbdb77c4SRichard Henderson { 1497dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1498dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14999df297a2SRichard Henderson tcg_gen_extrl_i64_i32(dest, t64); 1500dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1501a1b48e3aSEdgar E. Iglesias } 1502aa28e6d4SRichard Henderson break; 1503351527b7SEdgar E. Iglesias case SR_ESR: 15049df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr)); 1505aa28e6d4SRichard Henderson break; 1506351527b7SEdgar E. Iglesias case SR_FSR: 15079df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr)); 1508aa28e6d4SRichard Henderson break; 1509351527b7SEdgar E. Iglesias case SR_BTR: 15109df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr)); 1511aa28e6d4SRichard Henderson break; 15127cdae31dSTong Ho case SR_EDR: 15139df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr)); 1514fcf5ef2aSThomas Huth break; 1515fcf5ef2aSThomas Huth case 0x800: 15169df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr)); 1517fcf5ef2aSThomas Huth break; 1518fcf5ef2aSThomas Huth case 0x802: 15199df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr)); 1520fcf5ef2aSThomas Huth break; 15219df297a2SRichard Henderson 15229df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 15239df297a2SRichard Henderson case 0x1000: /* PID */ 15249df297a2SRichard Henderson case 0x1001: /* ZPR */ 15259df297a2SRichard Henderson case 0x1002: /* TLBX */ 15269df297a2SRichard Henderson case 0x1003: /* TLBLO */ 15279df297a2SRichard Henderson case 0x1004: /* TLBHI */ 15289df297a2SRichard Henderson case 0x1005: /* TLBSX */ 15299df297a2SRichard Henderson { 15309df297a2SRichard Henderson TCGv_i32 tmp_ext = tcg_const_i32(arg->e); 15319df297a2SRichard Henderson TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); 15329df297a2SRichard Henderson 15339df297a2SRichard Henderson gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg); 15349df297a2SRichard Henderson tcg_temp_free_i32(tmp_reg); 15359df297a2SRichard Henderson tcg_temp_free_i32(tmp_ext); 15369df297a2SRichard Henderson } 15379df297a2SRichard Henderson break; 15389df297a2SRichard Henderson #endif 15399df297a2SRichard Henderson 1540351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 15419df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, 1542a4bcfc33SRichard Henderson offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000]) 1543a4bcfc33SRichard Henderson - offsetof(MicroBlazeCPU, env)); 1544fcf5ef2aSThomas Huth break; 1545fcf5ef2aSThomas Huth default: 15469df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs); 1547fcf5ef2aSThomas Huth break; 1548fcf5ef2aSThomas Huth } 15499df297a2SRichard Henderson return true; 1550fcf5ef2aSThomas Huth } 1551fcf5ef2aSThomas Huth 15523fb394fdSRichard Henderson static void do_rti(DisasContext *dc) 1553fcf5ef2aSThomas Huth { 15543fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1555fcf5ef2aSThomas Huth 15563fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15573fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE); 15583fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM); 15593fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM)); 15603fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 15613fb394fdSRichard Henderson 15623fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1563fcf5ef2aSThomas Huth } 1564fcf5ef2aSThomas Huth 15653fb394fdSRichard Henderson static void do_rtb(DisasContext *dc) 1566fcf5ef2aSThomas Huth { 15673fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1568fcf5ef2aSThomas Huth 15693fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15703fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP)); 15713fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15723fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 15733fb394fdSRichard Henderson 15743fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1575fcf5ef2aSThomas Huth } 1576fcf5ef2aSThomas Huth 15773fb394fdSRichard Henderson static void do_rte(DisasContext *dc) 1578fcf5ef2aSThomas Huth { 15793fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1580fcf5ef2aSThomas Huth 15813fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15823fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE); 15833fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15843fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP)); 15853fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1586fcf5ef2aSThomas Huth 15873fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1588fcf5ef2aSThomas Huth } 1589fcf5ef2aSThomas Huth 1590fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 159152065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl) 1592fcf5ef2aSThomas Huth { 1593fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1594fcf5ef2aSThomas Huth 1595bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 159652065d8fSRichard Henderson return true; 1597fcf5ef2aSThomas Huth } 1598fcf5ef2aSThomas Huth 1599cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 160052065d8fSRichard Henderson if (rb) { 160152065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 1602fcf5ef2aSThomas Huth } else { 160352065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 1604fcf5ef2aSThomas Huth } 1605fcf5ef2aSThomas Huth 1606cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 160752065d8fSRichard Henderson gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl); 1608cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1609cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 161052065d8fSRichard Henderson return true; 161152065d8fSRichard Henderson } 161252065d8fSRichard Henderson 161352065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg) 161452065d8fSRichard Henderson { 161552065d8fSRichard Henderson return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl); 161652065d8fSRichard Henderson } 161752065d8fSRichard Henderson 161852065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg) 161952065d8fSRichard Henderson { 162052065d8fSRichard Henderson return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl); 162152065d8fSRichard Henderson } 162252065d8fSRichard Henderson 162352065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl) 162452065d8fSRichard Henderson { 162552065d8fSRichard Henderson TCGv_i32 t_id, t_ctrl; 162652065d8fSRichard Henderson 162752065d8fSRichard Henderson if (trap_userspace(dc, true)) { 162852065d8fSRichard Henderson return true; 162952065d8fSRichard Henderson } 163052065d8fSRichard Henderson 163152065d8fSRichard Henderson t_id = tcg_temp_new_i32(); 163252065d8fSRichard Henderson if (rb) { 163352065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 163452065d8fSRichard Henderson } else { 163552065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 163652065d8fSRichard Henderson } 163752065d8fSRichard Henderson 163852065d8fSRichard Henderson t_ctrl = tcg_const_i32(ctrl); 163952065d8fSRichard Henderson gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra)); 164052065d8fSRichard Henderson tcg_temp_free_i32(t_id); 164152065d8fSRichard Henderson tcg_temp_free_i32(t_ctrl); 164252065d8fSRichard Henderson return true; 164352065d8fSRichard Henderson } 164452065d8fSRichard Henderson 164552065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg) 164652065d8fSRichard Henderson { 164752065d8fSRichard Henderson return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl); 164852065d8fSRichard Henderson } 164952065d8fSRichard Henderson 165052065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg) 165152065d8fSRichard Henderson { 165252065d8fSRichard Henderson return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); 1653fcf5ef2aSThomas Huth } 1654fcf5ef2aSThomas Huth 1655372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1656fcf5ef2aSThomas Huth { 1657372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1658372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1659372122e3SRichard Henderson int bound; 1660fcf5ef2aSThomas Huth 16614b893631SRichard Henderson dc->cfg = &cpu->cfg; 1662683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags; 1663d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 166420800179SRichard Henderson dc->r0 = NULL; 166520800179SRichard Henderson dc->r0_set = false; 1666287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 1667b9c58aabSRichard Henderson dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; 1668b9c58aabSRichard Henderson dc->jmp_dest = -1; 1669fcf5ef2aSThomas Huth 1670372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1671372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1672fcf5ef2aSThomas Huth } 1673fcf5ef2aSThomas Huth 1674372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1675fcf5ef2aSThomas Huth { 1676fcf5ef2aSThomas Huth } 1677fcf5ef2aSThomas Huth 1678372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1679372122e3SRichard Henderson { 1680683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1681683a247eSRichard Henderson 1682683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); 1683683a247eSRichard Henderson dc->insn_start = tcg_last_op(); 1684372122e3SRichard Henderson } 1685fcf5ef2aSThomas Huth 1686372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1687372122e3SRichard Henderson const CPUBreakpoint *bp) 1688372122e3SRichard Henderson { 1689372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1690372122e3SRichard Henderson 1691372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1692372122e3SRichard Henderson 1693372122e3SRichard Henderson /* 1694372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1695372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1696372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1697372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1698372122e3SRichard Henderson */ 1699372122e3SRichard Henderson dc->base.pc_next += 4; 1700372122e3SRichard Henderson return true; 1701372122e3SRichard Henderson } 1702372122e3SRichard Henderson 1703372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1704372122e3SRichard Henderson { 1705372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1706372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 170744d1432bSRichard Henderson uint32_t ir; 1708372122e3SRichard Henderson 1709372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1710372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1711372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1712372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1713fcf5ef2aSThomas Huth } 1714fcf5ef2aSThomas Huth 17156f9642d7SRichard Henderson dc->tb_flags_to_set = 0; 17166f9642d7SRichard Henderson 171744d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 171844d1432bSRichard Henderson if (!decode(dc, ir)) { 1719921afa9dSRichard Henderson trap_illegal(dc, true); 172044d1432bSRichard Henderson } 172120800179SRichard Henderson 172220800179SRichard Henderson if (dc->r0) { 172320800179SRichard Henderson tcg_temp_free_i32(dc->r0); 172420800179SRichard Henderson dc->r0 = NULL; 172520800179SRichard Henderson dc->r0_set = false; 172620800179SRichard Henderson } 172720800179SRichard Henderson 17286f9642d7SRichard Henderson /* Discard the imm global when its contents cannot be used. */ 17296f9642d7SRichard Henderson if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { 1730d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1731372122e3SRichard Henderson } 17326f9642d7SRichard Henderson 17331e521ce3SRichard Henderson dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG); 17346f9642d7SRichard Henderson dc->tb_flags |= dc->tb_flags_to_set; 1735d4705ae0SRichard Henderson dc->base.pc_next += 4; 1736fcf5ef2aSThomas Huth 1737b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { 17383d35bcc2SRichard Henderson /* 17393d35bcc2SRichard Henderson * Finish any return-from branch. 17403d35bcc2SRichard Henderson */ 17413c745866SRichard Henderson uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); 17423c745866SRichard Henderson if (unlikely(rt_ibe != 0)) { 17433c745866SRichard Henderson dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); 17443c745866SRichard Henderson if (rt_ibe & DRTI_FLAG) { 1745fcf5ef2aSThomas Huth do_rti(dc); 17463c745866SRichard Henderson } else if (rt_ibe & DRTB_FLAG) { 1747fcf5ef2aSThomas Huth do_rtb(dc); 17483c745866SRichard Henderson } else { 1749fcf5ef2aSThomas Huth do_rte(dc); 1750372122e3SRichard Henderson } 17513c745866SRichard Henderson } 17523d35bcc2SRichard Henderson 17533d35bcc2SRichard Henderson /* Complete the branch, ending the TB. */ 17543d35bcc2SRichard Henderson switch (dc->base.is_jmp) { 17553d35bcc2SRichard Henderson case DISAS_NORETURN: 17563d35bcc2SRichard Henderson /* 17573d35bcc2SRichard Henderson * E.g. illegal insn in a delay slot. We've already exited 17583d35bcc2SRichard Henderson * and will handle D_FLAG in mb_cpu_do_interrupt. 17593d35bcc2SRichard Henderson */ 17603d35bcc2SRichard Henderson break; 17613d35bcc2SRichard Henderson case DISAS_NEXT: 17623c745866SRichard Henderson /* 17633c745866SRichard Henderson * Normal insn a delay slot. 17643c745866SRichard Henderson * However, the return-from-exception type insns should 17653c745866SRichard Henderson * return to the main loop, as they have adjusted MSR. 17663c745866SRichard Henderson */ 17673c745866SRichard Henderson dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP); 17683d35bcc2SRichard Henderson break; 17693d35bcc2SRichard Henderson case DISAS_EXIT_NEXT: 17703d35bcc2SRichard Henderson /* 17713d35bcc2SRichard Henderson * E.g. mts insn in a delay slot. Continue with btarget, 17723d35bcc2SRichard Henderson * but still return to the main loop. 17733d35bcc2SRichard Henderson */ 17743d35bcc2SRichard Henderson dc->base.is_jmp = DISAS_EXIT_JUMP; 17753d35bcc2SRichard Henderson break; 17763d35bcc2SRichard Henderson default: 17773d35bcc2SRichard Henderson g_assert_not_reached(); 17783d35bcc2SRichard Henderson } 1779372122e3SRichard Henderson } 1780372122e3SRichard Henderson } 1781372122e3SRichard Henderson 1782372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1783372122e3SRichard Henderson { 1784372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1785372122e3SRichard Henderson 1786372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1787372122e3SRichard Henderson /* We have already exited the TB. */ 1788372122e3SRichard Henderson return; 1789372122e3SRichard Henderson } 1790372122e3SRichard Henderson 1791372122e3SRichard Henderson t_sync_flags(dc); 1792372122e3SRichard Henderson 1793372122e3SRichard Henderson switch (dc->base.is_jmp) { 1794372122e3SRichard Henderson case DISAS_TOO_MANY: 1795372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1796372122e3SRichard Henderson return; 1797372122e3SRichard Henderson 179817e77796SRichard Henderson case DISAS_EXIT: 1799f6278ca9SRichard Henderson break; 1800f6278ca9SRichard Henderson case DISAS_EXIT_NEXT: 1801f6278ca9SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1802f6278ca9SRichard Henderson break; 1803f6278ca9SRichard Henderson case DISAS_EXIT_JUMP: 1804f6278ca9SRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1805f6278ca9SRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1806f6278ca9SRichard Henderson break; 1807372122e3SRichard Henderson 1808372122e3SRichard Henderson case DISAS_JUMP: 1809b9c58aabSRichard Henderson if (dc->jmp_dest != -1 && !cs->singlestep_enabled) { 1810b9c58aabSRichard Henderson /* Direct jump. */ 1811b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1812b9c58aabSRichard Henderson 1813b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_ALWAYS) { 1814b9c58aabSRichard Henderson /* Conditional direct jump. */ 1815b9c58aabSRichard Henderson TCGLabel *taken = gen_new_label(); 1816b9c58aabSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1817b9c58aabSRichard Henderson 1818b9c58aabSRichard Henderson /* 1819b9c58aabSRichard Henderson * Copy bvalue to a temp now, so we can discard bvalue. 1820b9c58aabSRichard Henderson * This can avoid writing bvalue to memory when the 1821b9c58aabSRichard Henderson * delay slot cannot raise an exception. 1822b9c58aabSRichard Henderson */ 1823b9c58aabSRichard Henderson tcg_gen_mov_i32(tmp, cpu_bvalue); 1824b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_bvalue); 1825b9c58aabSRichard Henderson 1826b9c58aabSRichard Henderson tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken); 1827b9c58aabSRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1828b9c58aabSRichard Henderson gen_set_label(taken); 1829b9c58aabSRichard Henderson } 1830b9c58aabSRichard Henderson gen_goto_tb(dc, 0, dc->jmp_dest); 1831b9c58aabSRichard Henderson return; 1832b9c58aabSRichard Henderson } 1833b9c58aabSRichard Henderson 1834b9c58aabSRichard Henderson /* Indirect jump (or direct jump w/ singlestep) */ 1835b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1836b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1837372122e3SRichard Henderson 1838372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1839372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1840372122e3SRichard Henderson } else { 18414059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr(); 1842372122e3SRichard Henderson } 1843372122e3SRichard Henderson return; 1844372122e3SRichard Henderson 1845a2b80dbdSRichard Henderson default: 1846a2b80dbdSRichard Henderson g_assert_not_reached(); 1847fcf5ef2aSThomas Huth } 1848f6278ca9SRichard Henderson 1849f6278ca9SRichard Henderson /* Finish DISAS_EXIT_* */ 1850f6278ca9SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1851f6278ca9SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1852f6278ca9SRichard Henderson } else { 1853f6278ca9SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1854f6278ca9SRichard Henderson } 1855fcf5ef2aSThomas Huth } 1856fcf5ef2aSThomas Huth 1857372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1858372122e3SRichard Henderson { 1859372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1860372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 1861fcf5ef2aSThomas Huth } 1862372122e3SRichard Henderson 1863372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1864372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1865372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1866372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1867372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1868372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1869372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1870372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1871372122e3SRichard Henderson }; 1872372122e3SRichard Henderson 1873372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1874372122e3SRichard Henderson { 1875372122e3SRichard Henderson DisasContext dc; 1876372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 1877fcf5ef2aSThomas Huth } 1878fcf5ef2aSThomas Huth 187990c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1880fcf5ef2aSThomas Huth { 1881fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1882fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 18830c3da918SRichard Henderson uint32_t iflags; 1884fcf5ef2aSThomas Huth int i; 1885fcf5ef2aSThomas Huth 18860c3da918SRichard Henderson qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n", 18870c3da918SRichard Henderson env->pc, env->msr, 18882e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18892e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18902e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18912e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18920c3da918SRichard Henderson 18930c3da918SRichard Henderson iflags = env->iflags; 18940c3da918SRichard Henderson qemu_fprintf(f, "iflags: 0x%08x", iflags); 18950c3da918SRichard Henderson if (iflags & IMM_FLAG) { 18960c3da918SRichard Henderson qemu_fprintf(f, " IMM(0x%08x)", env->imm); 18972ead1b18SJoe Komlodi } 18980c3da918SRichard Henderson if (iflags & BIMM_FLAG) { 18990c3da918SRichard Henderson qemu_fprintf(f, " BIMM"); 19000c3da918SRichard Henderson } 19010c3da918SRichard Henderson if (iflags & D_FLAG) { 1902b9c58aabSRichard Henderson qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget); 19030c3da918SRichard Henderson } 19040c3da918SRichard Henderson if (iflags & DRTI_FLAG) { 19050c3da918SRichard Henderson qemu_fprintf(f, " DRTI"); 19060c3da918SRichard Henderson } 19070c3da918SRichard Henderson if (iflags & DRTE_FLAG) { 19080c3da918SRichard Henderson qemu_fprintf(f, " DRTE"); 19090c3da918SRichard Henderson } 19100c3da918SRichard Henderson if (iflags & DRTB_FLAG) { 19110c3da918SRichard Henderson qemu_fprintf(f, " DRTB"); 19120c3da918SRichard Henderson } 19130c3da918SRichard Henderson if (iflags & ESR_ESS_FLAG) { 19140c3da918SRichard Henderson qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK); 19152ead1b18SJoe Komlodi } 1916fcf5ef2aSThomas Huth 19170c3da918SRichard Henderson qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" 191819f27b6cSRichard Henderson "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n", 19190c3da918SRichard Henderson env->esr, env->fsr, env->btr, env->edr, 19200c3da918SRichard Henderson env->ear, env->slr, env->shr); 19210c3da918SRichard Henderson 19220c3da918SRichard Henderson for (i = 0; i < 32; i++) { 19230c3da918SRichard Henderson qemu_fprintf(f, "r%2.2d=%08x%c", 19240c3da918SRichard Henderson i, env->regs[i], i % 4 == 3 ? '\n' : ' '); 19250c3da918SRichard Henderson } 19260c3da918SRichard Henderson qemu_fprintf(f, "\n"); 1927fcf5ef2aSThomas Huth } 1928fcf5ef2aSThomas Huth 1929fcf5ef2aSThomas Huth void mb_tcg_init(void) 1930fcf5ef2aSThomas Huth { 1931480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1932480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1933fcf5ef2aSThomas Huth 1934480d29a8SRichard Henderson static const struct { 1935480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1936480d29a8SRichard Henderson } i32s[] = { 1937e47c2231SRichard Henderson /* 1938e47c2231SRichard Henderson * Note that r0 is handled specially in reg_for_read 1939e47c2231SRichard Henderson * and reg_for_write. Nothing should touch cpu_R[0]. 1940e47c2231SRichard Henderson * Leave that element NULL, which will assert quickly 1941e47c2231SRichard Henderson * inside the tcg generator functions. 1942e47c2231SRichard Henderson */ 1943e47c2231SRichard Henderson R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1944480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1945480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1946480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1947480d29a8SRichard Henderson 1948480d29a8SRichard Henderson SP(pc), 1949480d29a8SRichard Henderson SP(msr), 19501074c0fbSRichard Henderson SP(msr_c), 1951480d29a8SRichard Henderson SP(imm), 1952480d29a8SRichard Henderson SP(iflags), 1953b9c58aabSRichard Henderson SP(bvalue), 1954480d29a8SRichard Henderson SP(btarget), 1955480d29a8SRichard Henderson SP(res_val), 1956480d29a8SRichard Henderson }; 1957480d29a8SRichard Henderson 1958480d29a8SRichard Henderson #undef R 1959480d29a8SRichard Henderson #undef SP 1960480d29a8SRichard Henderson 1961480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1962480d29a8SRichard Henderson *i32s[i].var = 1963480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1964fcf5ef2aSThomas Huth } 196576e8187dSRichard Henderson 1966480d29a8SRichard Henderson cpu_res_addr = 1967480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1968fcf5ef2aSThomas Huth } 1969fcf5ef2aSThomas Huth 1970fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1971fcf5ef2aSThomas Huth target_ulong *data) 1972fcf5ef2aSThomas Huth { 197376e8187dSRichard Henderson env->pc = data[0]; 1974683a247eSRichard Henderson env->iflags = data[1]; 1975fcf5ef2aSThomas Huth } 1976