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 10ee452036SChetan 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 "exec/log.h" 33fcf5ef2aSThomas Huth 34fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 35fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 36fcf5ef2aSThomas Huth 3777fc6f5eSLluís Vilanova /* is_jmp field values */ 3877fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 3917e77796SRichard Henderson #define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */ 4077fc6f5eSLluís Vilanova 41f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */ 42f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2 43f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */ 44f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3 45f6278ca9SRichard Henderson 46cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 470f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 483e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 491074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 509b158558SRichard Henderson static TCGv_i32 cpu_imm; 51b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue; 520f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 539b158558SRichard Henderson static TCGv_i32 cpu_iflags; 549b158558SRichard Henderson static TCGv cpu_res_addr; 559b158558SRichard Henderson static TCGv_i32 cpu_res_val; 56fcf5ef2aSThomas Huth 57fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 58fcf5ef2aSThomas Huth 59fcf5ef2aSThomas Huth /* This is the state at translation time. */ 60fcf5ef2aSThomas Huth typedef struct DisasContext { 61d4705ae0SRichard Henderson DisasContextBase base; 624b893631SRichard Henderson const MicroBlazeCPUConfig *cfg; 63fcf5ef2aSThomas Huth 64683a247eSRichard Henderson /* TCG op of the current insn_start. */ 65683a247eSRichard Henderson TCGOp *insn_start; 66683a247eSRichard Henderson 6720800179SRichard Henderson TCGv_i32 r0; 6820800179SRichard Henderson bool r0_set; 6920800179SRichard Henderson 70fcf5ef2aSThomas Huth /* Decoder. */ 71d7ecb757SRichard Henderson uint32_t ext_imm; 72683a247eSRichard Henderson unsigned int tb_flags; 736f9642d7SRichard Henderson unsigned int tb_flags_to_set; 74287b1defSRichard Henderson int mem_index; 75fcf5ef2aSThomas Huth 76b9c58aabSRichard Henderson /* Condition under which to jump, including NEVER and ALWAYS. */ 77b9c58aabSRichard Henderson TCGCond jmp_cond; 78b9c58aabSRichard Henderson 79b9c58aabSRichard Henderson /* Immediate branch-taken destination, or -1 for indirect. */ 80b9c58aabSRichard Henderson uint32_t jmp_dest; 81fcf5ef2aSThomas Huth } DisasContext; 82fcf5ef2aSThomas Huth 8320800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8420800179SRichard Henderson { 8520800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 8620800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 8720800179SRichard Henderson } 8820800179SRichard Henderson return x; 8920800179SRichard Henderson } 9020800179SRichard Henderson 9144d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9244d1432bSRichard Henderson #include "decode-insns.c.inc" 9344d1432bSRichard Henderson 94683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc) 95fcf5ef2aSThomas Huth { 96fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 9788e74b61SRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) { 9888e74b61SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK); 99fcf5ef2aSThomas Huth } 100fcf5ef2aSThomas Huth } 101fcf5ef2aSThomas Huth 10241ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 103fcf5ef2aSThomas Huth { 104fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 105fcf5ef2aSThomas Huth 106fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 107fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 108d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 109fcf5ef2aSThomas Huth } 110fcf5ef2aSThomas Huth 11141ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11241ba37c4SRichard Henderson { 11341ba37c4SRichard Henderson t_sync_flags(dc); 114d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 11541ba37c4SRichard Henderson gen_raise_exception(dc, index); 11641ba37c4SRichard Henderson } 11741ba37c4SRichard Henderson 11841ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 11941ba37c4SRichard Henderson { 12041ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12141ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12241ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12341ba37c4SRichard Henderson 12441ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 12541ba37c4SRichard Henderson } 12641ba37c4SRichard Henderson 127fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 128fcf5ef2aSThomas Huth { 129*66345580SRichard Henderson if (translator_use_goto_tb(&dc->base, dest)) { 130fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1310f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 132d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 133fcf5ef2aSThomas Huth } else { 1340f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1354059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr(); 136fcf5ef2aSThomas Huth } 137d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 138fcf5ef2aSThomas Huth } 139fcf5ef2aSThomas Huth 140bdfc1e88SEdgar E. Iglesias /* 1419ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1429ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1439ba8cd45SEdgar E. Iglesias */ 1449ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1459ba8cd45SEdgar E. Iglesias { 1462c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE) 1474b893631SRichard Henderson && dc->cfg->illegal_opcode_exception) { 14841ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1499ba8cd45SEdgar E. Iglesias } 1509ba8cd45SEdgar E. Iglesias return cond; 1519ba8cd45SEdgar E. Iglesias } 1529ba8cd45SEdgar E. Iglesias 1539ba8cd45SEdgar E. Iglesias /* 154bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 155bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 156bdfc1e88SEdgar E. Iglesias */ 157bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 158bdfc1e88SEdgar E. Iglesias { 159287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX; 160bdfc1e88SEdgar E. Iglesias 1612c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) { 16241ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 163bdfc1e88SEdgar E. Iglesias } 164bdfc1e88SEdgar E. Iglesias return cond_user; 165bdfc1e88SEdgar E. Iglesias } 166bdfc1e88SEdgar E. Iglesias 1672a7567a2SRichard Henderson /* 1682a7567a2SRichard Henderson * Return true, and log an error, if the current insn is 1692a7567a2SRichard Henderson * within a delay slot. 1702a7567a2SRichard Henderson */ 1712a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type) 1722a7567a2SRichard Henderson { 1732a7567a2SRichard Henderson if (dc->tb_flags & D_FLAG) { 1742a7567a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 1752a7567a2SRichard Henderson "Invalid insn in delay slot: %s at %08x\n", 1762a7567a2SRichard Henderson insn_type, (uint32_t)dc->base.pc_next); 1772a7567a2SRichard Henderson return true; 1782a7567a2SRichard Henderson } 1792a7567a2SRichard Henderson return false; 1802a7567a2SRichard Henderson } 1812a7567a2SRichard Henderson 18220800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 183fcf5ef2aSThomas Huth { 18420800179SRichard Henderson if (likely(reg != 0)) { 18520800179SRichard Henderson return cpu_R[reg]; 186fcf5ef2aSThomas Huth } 18720800179SRichard Henderson if (!dc->r0_set) { 18820800179SRichard Henderson if (dc->r0 == NULL) { 18920800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 190fcf5ef2aSThomas Huth } 19120800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 19220800179SRichard Henderson dc->r0_set = true; 19320800179SRichard Henderson } 19420800179SRichard Henderson return dc->r0; 195fcf5ef2aSThomas Huth } 196fcf5ef2aSThomas Huth 19720800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 19820800179SRichard Henderson { 19920800179SRichard Henderson if (likely(reg != 0)) { 20020800179SRichard Henderson return cpu_R[reg]; 20120800179SRichard Henderson } 20220800179SRichard Henderson if (dc->r0 == NULL) { 20320800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 20420800179SRichard Henderson } 20520800179SRichard Henderson return dc->r0; 206fcf5ef2aSThomas Huth } 207fcf5ef2aSThomas Huth 20820800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 20920800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 21020800179SRichard Henderson { 21120800179SRichard Henderson TCGv_i32 rd, ra, rb; 21220800179SRichard Henderson 21320800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 21420800179SRichard Henderson return true; 215fcf5ef2aSThomas Huth } 21620800179SRichard Henderson 21720800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 21820800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 21920800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 22020800179SRichard Henderson fn(rd, ra, rb); 22120800179SRichard Henderson return true; 22220800179SRichard Henderson } 22320800179SRichard Henderson 22439cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, 22539cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32)) 22639cf3864SRichard Henderson { 22739cf3864SRichard Henderson TCGv_i32 rd, ra; 22839cf3864SRichard Henderson 22939cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) { 23039cf3864SRichard Henderson return true; 23139cf3864SRichard Henderson } 23239cf3864SRichard Henderson 23339cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd); 23439cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra); 23539cf3864SRichard Henderson fn(rd, ra); 23639cf3864SRichard Henderson return true; 23739cf3864SRichard Henderson } 23839cf3864SRichard Henderson 23920800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 24020800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 24120800179SRichard Henderson { 24220800179SRichard Henderson TCGv_i32 rd, ra; 24320800179SRichard Henderson 24420800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 24520800179SRichard Henderson return true; 24620800179SRichard Henderson } 24720800179SRichard Henderson 24820800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 24920800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 25020800179SRichard Henderson fni(rd, ra, arg->imm); 25120800179SRichard Henderson return true; 25220800179SRichard Henderson } 25320800179SRichard Henderson 25420800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 25520800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 25620800179SRichard Henderson { 25720800179SRichard Henderson TCGv_i32 rd, ra, imm; 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 imm = tcg_const_i32(arg->imm); 26620800179SRichard Henderson 26720800179SRichard Henderson fn(rd, ra, imm); 26820800179SRichard Henderson 26920800179SRichard Henderson tcg_temp_free_i32(imm); 27020800179SRichard Henderson return true; 27120800179SRichard Henderson } 27220800179SRichard Henderson 27320800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 27420800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 27520800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 27620800179SRichard Henderson 277607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 278607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 2794b893631SRichard Henderson { return dc->cfg->CFG && do_typea(dc, a, SE, FN); } 280607f5767SRichard Henderson 28139cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 28239cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 28339cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 28439cf3864SRichard Henderson 28539cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 28639cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 2874b893631SRichard Henderson { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); } 28839cf3864SRichard Henderson 28920800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 29020800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29120800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 29220800179SRichard Henderson 29397955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 29497955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 2954b893631SRichard Henderson { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); } 29697955cebSRichard Henderson 29720800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 29820800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29920800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 30020800179SRichard Henderson 301d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 302d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 303d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 304d5aead3dSRichard Henderson 305d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 306d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 307d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 308d5aead3dSRichard Henderson 30920800179SRichard Henderson /* No input carry, but output carry. */ 31020800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 31120800179SRichard Henderson { 31220800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 31320800179SRichard Henderson 31420800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 31520800179SRichard Henderson 31620800179SRichard Henderson tcg_temp_free_i32(zero); 31720800179SRichard Henderson } 31820800179SRichard Henderson 31920800179SRichard Henderson /* Input and output carry. */ 32020800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 32120800179SRichard Henderson { 32220800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 32320800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 32420800179SRichard Henderson 32520800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 32620800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 32720800179SRichard Henderson 32820800179SRichard Henderson tcg_temp_free_i32(tmp); 32920800179SRichard Henderson tcg_temp_free_i32(zero); 33020800179SRichard Henderson } 33120800179SRichard Henderson 33220800179SRichard Henderson /* Input carry, but no output carry. */ 33320800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 33420800179SRichard Henderson { 33520800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 33620800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 33720800179SRichard Henderson } 33820800179SRichard Henderson 33920800179SRichard Henderson DO_TYPEA(add, true, gen_add) 34020800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 34120800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 34220800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 34320800179SRichard Henderson 34420800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 34520800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 34620800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 34720800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 34820800179SRichard Henderson 349cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 350cb0a0a4cSRichard Henderson { 351cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 352cb0a0a4cSRichard Henderson } 353cb0a0a4cSRichard Henderson 354cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 355cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 356cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 357cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 358cb0a0a4cSRichard Henderson 359081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 360081d8e02SRichard Henderson { 361081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 362081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 363081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 364081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 365081d8e02SRichard Henderson } 366081d8e02SRichard Henderson 367081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 368081d8e02SRichard Henderson { 369081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 370081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 371081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 372081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 373081d8e02SRichard Henderson } 374081d8e02SRichard Henderson 375081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 376081d8e02SRichard Henderson { 377081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 378081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 379081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 380081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 381081d8e02SRichard Henderson } 382081d8e02SRichard Henderson 383081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 384081d8e02SRichard Henderson { 385081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 386081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 387081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 388081d8e02SRichard Henderson 389081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 390081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 391081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 392081d8e02SRichard Henderson imm_w, imm_s); 393081d8e02SRichard Henderson } else { 394081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 395081d8e02SRichard Henderson } 396081d8e02SRichard Henderson } 397081d8e02SRichard Henderson 398081d8e02SRichard Henderson static void gen_bsifi(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 int width = imm_w - imm_s + 1; 404081d8e02SRichard Henderson 405081d8e02SRichard Henderson if (imm_w < imm_s) { 406081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 407081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 408081d8e02SRichard Henderson imm_w, imm_s); 409081d8e02SRichard Henderson } else { 410081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 411081d8e02SRichard Henderson } 412081d8e02SRichard Henderson } 413081d8e02SRichard Henderson 414081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 415081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 416081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 417081d8e02SRichard Henderson 418081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 419081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 420081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 421081d8e02SRichard Henderson 422081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 423081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 424081d8e02SRichard Henderson 42539cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 42639cf3864SRichard Henderson { 42739cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 42839cf3864SRichard Henderson } 42939cf3864SRichard Henderson 43039cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 43139cf3864SRichard Henderson 43258b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 43358b48b63SRichard Henderson { 43458b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 43558b48b63SRichard Henderson 43658b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 43758b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 43858b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 43958b48b63SRichard Henderson tcg_temp_free_i32(lt); 44058b48b63SRichard Henderson } 44158b48b63SRichard Henderson 44258b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 44358b48b63SRichard Henderson { 44458b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 44558b48b63SRichard Henderson 44658b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 44758b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 44858b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 44958b48b63SRichard Henderson tcg_temp_free_i32(lt); 45058b48b63SRichard Henderson } 45158b48b63SRichard Henderson 45258b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 45358b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 454a2b0b90eSRichard Henderson 455d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 456d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 457d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 458d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 459d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 460d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 461d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 462d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 463d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 464d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 465d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 466d5aead3dSRichard Henderson 467d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 468d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 469d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 470d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 471d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 472d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 473d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 474d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 475d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 476d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 477d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 478d5aead3dSRichard Henderson 479d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 480d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 481d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 482d5aead3dSRichard Henderson 483d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 484d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 485d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 486d5aead3dSRichard Henderson 487d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 488b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 489b1354342SRichard Henderson { 490b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 491b1354342SRichard Henderson } 492b1354342SRichard Henderson 493b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 494b1354342SRichard Henderson { 495b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 496b1354342SRichard Henderson } 497b1354342SRichard Henderson 498b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 499b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 500b1354342SRichard Henderson 501e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 502e64b2e5cSRichard Henderson { 5032a7567a2SRichard Henderson if (invalid_delay_slot(dc, "imm")) { 5042a7567a2SRichard Henderson return true; 5052a7567a2SRichard Henderson } 506e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 507e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 5086f9642d7SRichard Henderson dc->tb_flags_to_set = IMM_FLAG; 509e64b2e5cSRichard Henderson return true; 510e64b2e5cSRichard Henderson } 511e64b2e5cSRichard Henderson 51297955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 51397955cebSRichard Henderson { 51497955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 51597955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 51697955cebSRichard Henderson tcg_temp_free_i32(tmp); 51797955cebSRichard Henderson } 51897955cebSRichard Henderson 51997955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 52097955cebSRichard Henderson { 52197955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 52297955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 52397955cebSRichard Henderson tcg_temp_free_i32(tmp); 52497955cebSRichard Henderson } 52597955cebSRichard Henderson 52697955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 52797955cebSRichard Henderson { 52897955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 52997955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 53097955cebSRichard Henderson tcg_temp_free_i32(tmp); 53197955cebSRichard Henderson } 53297955cebSRichard Henderson 53397955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 53497955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 53597955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 53697955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 53797955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 53897955cebSRichard Henderson 539cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 540cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 541cb0a0a4cSRichard Henderson 542607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 543607f5767SRichard Henderson { 544607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 545607f5767SRichard Henderson } 546607f5767SRichard Henderson 547607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 548607f5767SRichard Henderson { 549607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 550607f5767SRichard Henderson } 551607f5767SRichard Henderson 552607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 553607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 554607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 555607f5767SRichard Henderson 556a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 557a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 558a2b0b90eSRichard Henderson { 559a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 560a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 561a2b0b90eSRichard Henderson } 562a2b0b90eSRichard Henderson 563a2b0b90eSRichard Henderson /* Input and output carry. */ 564a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 565a2b0b90eSRichard Henderson { 566a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 567a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 568a2b0b90eSRichard Henderson 569a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 570a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 571a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 572a2b0b90eSRichard Henderson 573a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 574a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 575a2b0b90eSRichard Henderson } 576a2b0b90eSRichard Henderson 577a2b0b90eSRichard Henderson /* No input or output carry. */ 578a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 579a2b0b90eSRichard Henderson { 580a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 581a2b0b90eSRichard Henderson } 582a2b0b90eSRichard Henderson 583a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 584a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 585a2b0b90eSRichard Henderson { 586a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 587a2b0b90eSRichard Henderson 588a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 589a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 590a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 591a2b0b90eSRichard Henderson 592a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 593a2b0b90eSRichard Henderson } 594a2b0b90eSRichard Henderson 595a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 596a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 597a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 598a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 599a2b0b90eSRichard Henderson 600a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 601a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 602a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 603a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 604a2b0b90eSRichard Henderson 60539cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 60639cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 60739cf3864SRichard Henderson 60839cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 60939cf3864SRichard Henderson { 61039cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 61139cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 61239cf3864SRichard Henderson } 61339cf3864SRichard Henderson 61439cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 61539cf3864SRichard Henderson { 61639cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 61739cf3864SRichard Henderson 61839cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 61939cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 62039cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 62139cf3864SRichard Henderson 62239cf3864SRichard Henderson tcg_temp_free_i32(tmp); 62339cf3864SRichard Henderson } 62439cf3864SRichard Henderson 62539cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 62639cf3864SRichard Henderson { 62739cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 62839cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 62939cf3864SRichard Henderson } 63039cf3864SRichard Henderson 63139cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 63239cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 63339cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 63439cf3864SRichard Henderson 63539cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 63639cf3864SRichard Henderson { 63739cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 63839cf3864SRichard Henderson } 63939cf3864SRichard Henderson 64039cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 64139cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 64239cf3864SRichard Henderson 64339cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 64439cf3864SRichard Henderson { 64539cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 64639cf3864SRichard Henderson trap_userspace(dc, true); 64739cf3864SRichard Henderson return true; 64839cf3864SRichard Henderson } 64939cf3864SRichard Henderson 650cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 651cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 652cb0a0a4cSRichard Henderson 653d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 654d8e59c4aSRichard Henderson { 655d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 656d8e59c4aSRichard Henderson 657d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 658d8e59c4aSRichard Henderson if (ra && rb) { 659d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 660d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 661d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 662d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 663d8e59c4aSRichard Henderson } else if (ra) { 664d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 665d8e59c4aSRichard Henderson } else if (rb) { 666d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 667d8e59c4aSRichard Henderson } else { 668d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 669d8e59c4aSRichard Henderson } 670d8e59c4aSRichard Henderson 6714b893631SRichard Henderson if ((ra == 1 || rb == 1) && dc->cfg->stackprot) { 672d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 673d8e59c4aSRichard Henderson } 674d8e59c4aSRichard Henderson return ret; 675d8e59c4aSRichard Henderson } 676d8e59c4aSRichard Henderson 677d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 678d8e59c4aSRichard Henderson { 679d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 680d8e59c4aSRichard Henderson 681d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 682d8e59c4aSRichard Henderson if (ra) { 683d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 684d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 685d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 686d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 687d8e59c4aSRichard Henderson } else { 688d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 689d8e59c4aSRichard Henderson } 690d8e59c4aSRichard Henderson 6914b893631SRichard Henderson if (ra == 1 && dc->cfg->stackprot) { 692d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 693d8e59c4aSRichard Henderson } 694d8e59c4aSRichard Henderson return ret; 695d8e59c4aSRichard Henderson } 696d8e59c4aSRichard Henderson 69719f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY 698d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 699d8e59c4aSRichard Henderson { 7004b893631SRichard Henderson int addr_size = dc->cfg->addr_size; 701d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 702d8e59c4aSRichard Henderson 703d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 704d8e59c4aSRichard Henderson if (rb) { 705d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 706d8e59c4aSRichard Henderson } else { 707d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 708d8e59c4aSRichard Henderson } 709d8e59c4aSRichard Henderson } else { 710d8e59c4aSRichard Henderson if (rb) { 711d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 712d8e59c4aSRichard Henderson } else { 713d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 714d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 715d8e59c4aSRichard Henderson } 716d8e59c4aSRichard Henderson if (addr_size < 64) { 717d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 718d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 719d8e59c4aSRichard Henderson } 720d8e59c4aSRichard Henderson } 721d8e59c4aSRichard Henderson return ret; 722d8e59c4aSRichard Henderson } 72319f27b6cSRichard Henderson #endif 724d8e59c4aSRichard Henderson 725ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd, 726ab0c8d0fSRichard Henderson MemOp size, bool store) 727ab0c8d0fSRichard Henderson { 728ab0c8d0fSRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); 729ab0c8d0fSRichard Henderson 730ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG; 731ab0c8d0fSRichard Henderson iflags |= rd << 5; 732ab0c8d0fSRichard Henderson iflags |= store * ESR_S; 733ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W; 734ab0c8d0fSRichard Henderson 735ab0c8d0fSRichard Henderson tcg_set_insn_start_param(dc->insn_start, 1, iflags); 736ab0c8d0fSRichard Henderson } 737ab0c8d0fSRichard Henderson 738d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 739d8e59c4aSRichard Henderson int mem_index, bool rev) 740d8e59c4aSRichard Henderson { 741d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 742d8e59c4aSRichard Henderson 743d8e59c4aSRichard Henderson /* 744d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 745d8e59c4aSRichard Henderson * 746d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 747d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 748d8e59c4aSRichard Henderson */ 749d8e59c4aSRichard Henderson if (rev) { 750d8e59c4aSRichard Henderson if (size > MO_8) { 751d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 752d8e59c4aSRichard Henderson } 753d8e59c4aSRichard Henderson if (size < MO_32) { 754d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 755d8e59c4aSRichard Henderson } 756d8e59c4aSRichard Henderson } 757d8e59c4aSRichard Henderson 758ab0c8d0fSRichard Henderson if (size > MO_8 && 759ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 7604b893631SRichard Henderson dc->cfg->unaligned_exceptions) { 761ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false); 762ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 763d8e59c4aSRichard Henderson } 764d8e59c4aSRichard Henderson 765ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); 766d8e59c4aSRichard Henderson 767d8e59c4aSRichard Henderson tcg_temp_free(addr); 768d8e59c4aSRichard Henderson return true; 769d8e59c4aSRichard Henderson } 770d8e59c4aSRichard Henderson 771d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 772d8e59c4aSRichard Henderson { 773d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 774d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 775d8e59c4aSRichard Henderson } 776d8e59c4aSRichard Henderson 777d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 778d8e59c4aSRichard Henderson { 779d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 780d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 781d8e59c4aSRichard Henderson } 782d8e59c4aSRichard Henderson 783d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 784d8e59c4aSRichard Henderson { 785d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 786d8e59c4aSRichard Henderson return true; 787d8e59c4aSRichard Henderson } 78819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 78919f27b6cSRichard Henderson return true; 79019f27b6cSRichard Henderson #else 791d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 792d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 79319f27b6cSRichard Henderson #endif 794d8e59c4aSRichard Henderson } 795d8e59c4aSRichard Henderson 796d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 797d8e59c4aSRichard Henderson { 798d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 799d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 800d8e59c4aSRichard Henderson } 801d8e59c4aSRichard Henderson 802d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 803d8e59c4aSRichard Henderson { 804d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 805d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 806d8e59c4aSRichard Henderson } 807d8e59c4aSRichard Henderson 808d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 809d8e59c4aSRichard Henderson { 810d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 811d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 812d8e59c4aSRichard Henderson } 813d8e59c4aSRichard Henderson 814d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 815d8e59c4aSRichard Henderson { 816d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 817d8e59c4aSRichard Henderson return true; 818d8e59c4aSRichard Henderson } 81919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 82019f27b6cSRichard Henderson return true; 82119f27b6cSRichard Henderson #else 822d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 823d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 82419f27b6cSRichard Henderson #endif 825d8e59c4aSRichard Henderson } 826d8e59c4aSRichard Henderson 827d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 828d8e59c4aSRichard Henderson { 829d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 830d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 831d8e59c4aSRichard Henderson } 832d8e59c4aSRichard Henderson 833d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 834d8e59c4aSRichard Henderson { 835d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 836d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 837d8e59c4aSRichard Henderson } 838d8e59c4aSRichard Henderson 839d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 840d8e59c4aSRichard Henderson { 841d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 842d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 843d8e59c4aSRichard Henderson } 844d8e59c4aSRichard Henderson 845d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 846d8e59c4aSRichard Henderson { 847d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 848d8e59c4aSRichard Henderson return true; 849d8e59c4aSRichard Henderson } 85019f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 85119f27b6cSRichard Henderson return true; 85219f27b6cSRichard Henderson #else 853d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 854d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 85519f27b6cSRichard Henderson #endif 856d8e59c4aSRichard Henderson } 857d8e59c4aSRichard Henderson 858d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg) 859d8e59c4aSRichard Henderson { 860d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 861d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 862d8e59c4aSRichard Henderson } 863d8e59c4aSRichard Henderson 864d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg) 865d8e59c4aSRichard Henderson { 866d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 867d8e59c4aSRichard Henderson 868d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */ 869d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 870d8e59c4aSRichard Henderson 871d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); 872d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 873d8e59c4aSRichard Henderson tcg_temp_free(addr); 874d8e59c4aSRichard Henderson 875d8e59c4aSRichard Henderson if (arg->rd) { 876d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 877d8e59c4aSRichard Henderson } 878d8e59c4aSRichard Henderson 879d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 880d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 881d8e59c4aSRichard Henderson return true; 882d8e59c4aSRichard Henderson } 883d8e59c4aSRichard Henderson 884d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 885d8e59c4aSRichard Henderson int mem_index, bool rev) 886d8e59c4aSRichard Henderson { 887d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 888d8e59c4aSRichard Henderson 889d8e59c4aSRichard Henderson /* 890d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 891d8e59c4aSRichard Henderson * 892d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 893d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 894d8e59c4aSRichard Henderson */ 895d8e59c4aSRichard Henderson if (rev) { 896d8e59c4aSRichard Henderson if (size > MO_8) { 897d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 898d8e59c4aSRichard Henderson } 899d8e59c4aSRichard Henderson if (size < MO_32) { 900d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 901d8e59c4aSRichard Henderson } 902d8e59c4aSRichard Henderson } 903d8e59c4aSRichard Henderson 904ab0c8d0fSRichard Henderson if (size > MO_8 && 905ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 9064b893631SRichard Henderson dc->cfg->unaligned_exceptions) { 907ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true); 908ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 909d8e59c4aSRichard Henderson } 910d8e59c4aSRichard Henderson 911ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 912ab0c8d0fSRichard Henderson 913d8e59c4aSRichard Henderson tcg_temp_free(addr); 914d8e59c4aSRichard Henderson return true; 915d8e59c4aSRichard Henderson } 916d8e59c4aSRichard Henderson 917d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 918d8e59c4aSRichard Henderson { 919d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 920d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 921d8e59c4aSRichard Henderson } 922d8e59c4aSRichard Henderson 923d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 924d8e59c4aSRichard Henderson { 925d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 926d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 927d8e59c4aSRichard Henderson } 928d8e59c4aSRichard Henderson 929d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 930d8e59c4aSRichard Henderson { 931d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 932d8e59c4aSRichard Henderson return true; 933d8e59c4aSRichard Henderson } 93419f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 93519f27b6cSRichard Henderson return true; 93619f27b6cSRichard Henderson #else 937d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 938d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 93919f27b6cSRichard Henderson #endif 940d8e59c4aSRichard Henderson } 941d8e59c4aSRichard Henderson 942d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 943d8e59c4aSRichard Henderson { 944d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 945d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 946d8e59c4aSRichard Henderson } 947d8e59c4aSRichard Henderson 948d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg) 949d8e59c4aSRichard Henderson { 950d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 951d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 952d8e59c4aSRichard Henderson } 953d8e59c4aSRichard Henderson 954d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 955d8e59c4aSRichard Henderson { 956d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 957d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 958d8e59c4aSRichard Henderson } 959d8e59c4aSRichard Henderson 960d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 961d8e59c4aSRichard Henderson { 962d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 963d8e59c4aSRichard Henderson return true; 964d8e59c4aSRichard Henderson } 96519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 96619f27b6cSRichard Henderson return true; 96719f27b6cSRichard Henderson #else 968d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 969d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 97019f27b6cSRichard Henderson #endif 971d8e59c4aSRichard Henderson } 972d8e59c4aSRichard Henderson 973d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 974d8e59c4aSRichard Henderson { 975d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 976d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 977d8e59c4aSRichard Henderson } 978d8e59c4aSRichard Henderson 979d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 980d8e59c4aSRichard Henderson { 981d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 982d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 983d8e59c4aSRichard Henderson } 984d8e59c4aSRichard Henderson 985d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 986d8e59c4aSRichard Henderson { 987d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 988d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 989d8e59c4aSRichard Henderson } 990d8e59c4aSRichard Henderson 991d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 992d8e59c4aSRichard Henderson { 993d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 994d8e59c4aSRichard Henderson return true; 995d8e59c4aSRichard Henderson } 99619f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 99719f27b6cSRichard Henderson return true; 99819f27b6cSRichard Henderson #else 999d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 1000d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 100119f27b6cSRichard Henderson #endif 1002d8e59c4aSRichard Henderson } 1003d8e59c4aSRichard Henderson 1004d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 1005d8e59c4aSRichard Henderson { 1006d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 1007d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 1008d8e59c4aSRichard Henderson } 1009d8e59c4aSRichard Henderson 1010d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 1011d8e59c4aSRichard Henderson { 1012d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1013d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 1014d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 1015d8e59c4aSRichard Henderson TCGv_i32 tval; 1016d8e59c4aSRichard Henderson 1017d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 1018d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1019d8e59c4aSRichard Henderson 1020d8e59c4aSRichard Henderson /* 1021d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 1022d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 1023d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 1024d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 1025d8e59c4aSRichard Henderson */ 1026d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 1027d8e59c4aSRichard Henderson tcg_temp_free(addr); 1028d8e59c4aSRichard Henderson 1029d8e59c4aSRichard Henderson /* 1030d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 1031d8e59c4aSRichard Henderson * the reserved location. 1032d8e59c4aSRichard Henderson */ 1033d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1034d8e59c4aSRichard Henderson 1035d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1036d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1037d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1038d8e59c4aSRichard Henderson 1039d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1040d8e59c4aSRichard Henderson tcg_temp_free_i32(tval); 1041d8e59c4aSRichard Henderson 1042d8e59c4aSRichard Henderson /* Success */ 1043d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1044d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1045d8e59c4aSRichard Henderson 1046d8e59c4aSRichard Henderson /* Failure */ 1047d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1048d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1049d8e59c4aSRichard Henderson 1050d8e59c4aSRichard Henderson gen_set_label(swx_done); 1051d8e59c4aSRichard Henderson 1052d8e59c4aSRichard Henderson /* 1053d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1054d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1055d8e59c4aSRichard Henderson */ 1056d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1057d8e59c4aSRichard Henderson return true; 1058d8e59c4aSRichard Henderson } 1059d8e59c4aSRichard Henderson 106016bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b) 106116bbbbc9SRichard Henderson { 106216bbbbc9SRichard Henderson dc->tb_flags_to_set |= D_FLAG; 106316bbbbc9SRichard Henderson if (type_b && (dc->tb_flags & IMM_FLAG)) { 106416bbbbc9SRichard Henderson dc->tb_flags_to_set |= BIMM_FLAG; 106516bbbbc9SRichard Henderson } 106616bbbbc9SRichard Henderson } 106716bbbbc9SRichard Henderson 106816bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm, 106916bbbbc9SRichard Henderson bool delay, bool abs, int link) 107016bbbbc9SRichard Henderson { 107116bbbbc9SRichard Henderson uint32_t add_pc; 107216bbbbc9SRichard Henderson 10732a7567a2SRichard Henderson if (invalid_delay_slot(dc, "branch")) { 10742a7567a2SRichard Henderson return true; 10752a7567a2SRichard Henderson } 107616bbbbc9SRichard Henderson if (delay) { 107716bbbbc9SRichard Henderson setup_dslot(dc, dest_rb < 0); 107816bbbbc9SRichard Henderson } 107916bbbbc9SRichard Henderson 108016bbbbc9SRichard Henderson if (link) { 108116bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next); 108216bbbbc9SRichard Henderson } 108316bbbbc9SRichard Henderson 108416bbbbc9SRichard Henderson /* Store the branch taken destination into btarget. */ 108516bbbbc9SRichard Henderson add_pc = abs ? 0 : dc->base.pc_next; 108616bbbbc9SRichard Henderson if (dest_rb > 0) { 108716bbbbc9SRichard Henderson dc->jmp_dest = -1; 108816bbbbc9SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc); 108916bbbbc9SRichard Henderson } else { 109016bbbbc9SRichard Henderson dc->jmp_dest = add_pc + dest_imm; 109116bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 109216bbbbc9SRichard Henderson } 109316bbbbc9SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 109416bbbbc9SRichard Henderson return true; 109516bbbbc9SRichard Henderson } 109616bbbbc9SRichard Henderson 109716bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \ 109816bbbbc9SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \ 109916bbbbc9SRichard Henderson { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \ 110016bbbbc9SRichard Henderson static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \ 110116bbbbc9SRichard Henderson { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); } 110216bbbbc9SRichard Henderson 110316bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false) 110416bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false) 110516bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false) 110616bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false) 110716bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true) 110816bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true) 110916bbbbc9SRichard Henderson 1110fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm, 1111fd779113SRichard Henderson TCGCond cond, int ra, bool delay) 1112fd779113SRichard Henderson { 1113fd779113SRichard Henderson TCGv_i32 zero, next; 1114fd779113SRichard Henderson 11152a7567a2SRichard Henderson if (invalid_delay_slot(dc, "bcc")) { 11162a7567a2SRichard Henderson return true; 11172a7567a2SRichard Henderson } 1118fd779113SRichard Henderson if (delay) { 1119fd779113SRichard Henderson setup_dslot(dc, dest_rb < 0); 1120fd779113SRichard Henderson } 1121fd779113SRichard Henderson 1122fd779113SRichard Henderson dc->jmp_cond = cond; 1123fd779113SRichard Henderson 1124fd779113SRichard Henderson /* Cache the condition register in cpu_bvalue across any delay slot. */ 1125fd779113SRichard Henderson tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra)); 1126fd779113SRichard Henderson 1127fd779113SRichard Henderson /* Store the branch taken destination into btarget. */ 1128fd779113SRichard Henderson if (dest_rb > 0) { 1129fd779113SRichard Henderson dc->jmp_dest = -1; 1130fd779113SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next); 1131fd779113SRichard Henderson } else { 1132fd779113SRichard Henderson dc->jmp_dest = dc->base.pc_next + dest_imm; 1133fd779113SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 1134fd779113SRichard Henderson } 1135fd779113SRichard Henderson 1136fd779113SRichard Henderson /* Compute the final destination into btarget. */ 1137fd779113SRichard Henderson zero = tcg_const_i32(0); 1138fd779113SRichard Henderson next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4); 1139fd779113SRichard Henderson tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, 1140fd779113SRichard Henderson reg_for_read(dc, ra), zero, 1141fd779113SRichard Henderson cpu_btarget, next); 1142fd779113SRichard Henderson tcg_temp_free_i32(zero); 1143fd779113SRichard Henderson tcg_temp_free_i32(next); 1144fd779113SRichard Henderson 1145fd779113SRichard Henderson return true; 1146fd779113SRichard Henderson } 1147fd779113SRichard Henderson 1148fd779113SRichard Henderson #define DO_BCC(NAME, COND) \ 1149fd779113SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \ 1150fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \ 1151fd779113SRichard Henderson static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \ 1152fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \ 1153fd779113SRichard Henderson static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \ 1154fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \ 1155fd779113SRichard Henderson static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \ 1156fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); } 1157fd779113SRichard Henderson 1158fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ) 1159fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE) 1160fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT) 1161fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE) 1162fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT) 1163fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE) 1164fd779113SRichard Henderson 1165f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg) 1166f5235314SRichard Henderson { 1167f5235314SRichard Henderson if (trap_userspace(dc, true)) { 1168f5235314SRichard Henderson return true; 1169f5235314SRichard Henderson } 11702a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brk")) { 11712a7567a2SRichard Henderson return true; 11722a7567a2SRichard Henderson } 11732a7567a2SRichard Henderson 1174f5235314SRichard Henderson tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb)); 1175f5235314SRichard Henderson if (arg->rd) { 1176f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1177f5235314SRichard Henderson } 1178f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP); 1179f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1180f5235314SRichard Henderson 118117e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1182f5235314SRichard Henderson return true; 1183f5235314SRichard Henderson } 1184f5235314SRichard Henderson 1185f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) 1186f5235314SRichard Henderson { 1187f5235314SRichard Henderson uint32_t imm = arg->imm; 1188f5235314SRichard Henderson 1189f5235314SRichard Henderson if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) { 1190f5235314SRichard Henderson return true; 1191f5235314SRichard Henderson } 11922a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brki")) { 11932a7567a2SRichard Henderson return true; 11942a7567a2SRichard Henderson } 11952a7567a2SRichard Henderson 1196f5235314SRichard Henderson tcg_gen_movi_i32(cpu_pc, imm); 1197f5235314SRichard Henderson if (arg->rd) { 1198f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1199f5235314SRichard Henderson } 1200f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1201f5235314SRichard Henderson 1202f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY 1203f5235314SRichard Henderson switch (imm) { 1204f5235314SRichard Henderson case 0x8: /* syscall trap */ 1205f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_SYSCALL); 1206f5235314SRichard Henderson break; 1207f5235314SRichard Henderson case 0x18: /* debug trap */ 1208f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1209f5235314SRichard Henderson break; 1210f5235314SRichard Henderson default: /* eliminated with trap_userspace check */ 1211f5235314SRichard Henderson g_assert_not_reached(); 1212f5235314SRichard Henderson } 1213f5235314SRichard Henderson #else 1214f5235314SRichard Henderson uint32_t msr_to_set = 0; 1215f5235314SRichard Henderson 1216f5235314SRichard Henderson if (imm != 0x18) { 1217f5235314SRichard Henderson msr_to_set |= MSR_BIP; 1218f5235314SRichard Henderson } 1219f5235314SRichard Henderson if (imm == 0x8 || imm == 0x18) { 1220f5235314SRichard Henderson /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */ 1221f5235314SRichard Henderson msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1; 1222f5235314SRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, 1223f5235314SRichard Henderson ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM)); 1224f5235314SRichard Henderson } 1225f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set); 122617e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1227f5235314SRichard Henderson #endif 1228f5235314SRichard Henderson 1229f5235314SRichard Henderson return true; 1230f5235314SRichard Henderson } 1231f5235314SRichard Henderson 1232ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg) 1233ee8c7f9fSRichard Henderson { 1234ee8c7f9fSRichard Henderson int mbar_imm = arg->imm; 1235ee8c7f9fSRichard Henderson 12362a7567a2SRichard Henderson /* Note that mbar is a specialized branch instruction. */ 12372a7567a2SRichard Henderson if (invalid_delay_slot(dc, "mbar")) { 12382a7567a2SRichard Henderson return true; 12392a7567a2SRichard Henderson } 12402a7567a2SRichard Henderson 1241ee8c7f9fSRichard Henderson /* Data access memory barrier. */ 1242ee8c7f9fSRichard Henderson if ((mbar_imm & 2) == 0) { 1243ee8c7f9fSRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 1244ee8c7f9fSRichard Henderson } 1245ee8c7f9fSRichard Henderson 1246ee8c7f9fSRichard Henderson /* Sleep. */ 1247ee8c7f9fSRichard Henderson if (mbar_imm & 16) { 1248ee8c7f9fSRichard Henderson TCGv_i32 tmp_1; 1249ee8c7f9fSRichard Henderson 1250ee8c7f9fSRichard Henderson if (trap_userspace(dc, true)) { 1251ee8c7f9fSRichard Henderson /* Sleep is a privileged instruction. */ 1252ee8c7f9fSRichard Henderson return true; 1253ee8c7f9fSRichard Henderson } 1254ee8c7f9fSRichard Henderson 1255ee8c7f9fSRichard Henderson t_sync_flags(dc); 1256ee8c7f9fSRichard Henderson 1257ee8c7f9fSRichard Henderson tmp_1 = tcg_const_i32(1); 1258ee8c7f9fSRichard Henderson tcg_gen_st_i32(tmp_1, cpu_env, 1259ee8c7f9fSRichard Henderson -offsetof(MicroBlazeCPU, env) 1260ee8c7f9fSRichard Henderson +offsetof(CPUState, halted)); 1261ee8c7f9fSRichard Henderson tcg_temp_free_i32(tmp_1); 1262ee8c7f9fSRichard Henderson 1263ee8c7f9fSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1264ee8c7f9fSRichard Henderson 1265ee8c7f9fSRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1266ee8c7f9fSRichard Henderson } 1267ee8c7f9fSRichard Henderson 1268ee8c7f9fSRichard Henderson /* 1269ee8c7f9fSRichard Henderson * If !(mbar_imm & 1), this is an instruction access memory barrier 1270ee8c7f9fSRichard Henderson * and we need to end the TB so that we recognize self-modified 1271ee8c7f9fSRichard Henderson * code immediately. 1272ee8c7f9fSRichard Henderson * 1273ee8c7f9fSRichard Henderson * However, there are some data mbars that need the TB break 1274ee8c7f9fSRichard Henderson * (and return to main loop) to recognize interrupts right away. 1275ee8c7f9fSRichard Henderson * E.g. recognizing a change to an interrupt controller register. 1276ee8c7f9fSRichard Henderson * 1277ee8c7f9fSRichard Henderson * Therefore, choose to end the TB always. 1278ee8c7f9fSRichard Henderson */ 127943b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1280ee8c7f9fSRichard Henderson return true; 1281ee8c7f9fSRichard Henderson } 1282ee8c7f9fSRichard Henderson 1283e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set) 1284e6cb0354SRichard Henderson { 1285e6cb0354SRichard Henderson if (trap_userspace(dc, to_set)) { 1286e6cb0354SRichard Henderson return true; 1287e6cb0354SRichard Henderson } 12882a7567a2SRichard Henderson if (invalid_delay_slot(dc, "rts")) { 12892a7567a2SRichard Henderson return true; 12902a7567a2SRichard Henderson } 12912a7567a2SRichard Henderson 1292e6cb0354SRichard Henderson dc->tb_flags_to_set |= to_set; 1293e6cb0354SRichard Henderson setup_dslot(dc, true); 1294e6cb0354SRichard Henderson 1295e6cb0354SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 1296e6cb0354SRichard Henderson dc->jmp_dest = -1; 1297e6cb0354SRichard Henderson tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm); 1298e6cb0354SRichard Henderson return true; 1299e6cb0354SRichard Henderson } 1300e6cb0354SRichard Henderson 1301e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \ 1302e6cb0354SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \ 1303e6cb0354SRichard Henderson { return do_rts(dc, arg, IFLAG); } 1304e6cb0354SRichard Henderson 1305e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG) 1306e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG) 1307e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG) 1308e6cb0354SRichard Henderson DO_RTS(rtsd, 0) 1309e6cb0354SRichard Henderson 131020800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 131120800179SRichard Henderson { 131220800179SRichard Henderson /* If opcode_0_illegal, trap. */ 13134b893631SRichard Henderson if (dc->cfg->opcode_0_illegal) { 131420800179SRichard Henderson trap_illegal(dc, true); 131520800179SRichard Henderson return true; 131620800179SRichard Henderson } 131720800179SRichard Henderson /* 131820800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 131920800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 132020800179SRichard Henderson */ 132120800179SRichard Henderson return false; 1322fcf5ef2aSThomas Huth } 1323fcf5ef2aSThomas Huth 13241074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 1325fcf5ef2aSThomas Huth { 13261074c0fbSRichard Henderson TCGv_i32 t; 13271074c0fbSRichard Henderson 13281074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 13291074c0fbSRichard Henderson t = tcg_temp_new_i32(); 13301074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 13311074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 13321074c0fbSRichard Henderson tcg_temp_free_i32(t); 1333fcf5ef2aSThomas Huth } 1334fcf5ef2aSThomas Huth 1335536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) 1336536e340fSRichard Henderson { 1337536e340fSRichard Henderson uint32_t imm = arg->imm; 1338536e340fSRichard Henderson 1339536e340fSRichard Henderson if (trap_userspace(dc, imm != MSR_C)) { 1340536e340fSRichard Henderson return true; 1341536e340fSRichard Henderson } 1342536e340fSRichard Henderson 1343536e340fSRichard Henderson if (arg->rd) { 1344536e340fSRichard Henderson msr_read(dc, cpu_R[arg->rd]); 1345536e340fSRichard Henderson } 1346536e340fSRichard Henderson 1347536e340fSRichard Henderson /* 1348536e340fSRichard Henderson * Handle the carry bit separately. 1349536e340fSRichard Henderson * This is the only bit that userspace can modify. 1350536e340fSRichard Henderson */ 1351536e340fSRichard Henderson if (imm & MSR_C) { 1352536e340fSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, set); 1353536e340fSRichard Henderson } 1354536e340fSRichard Henderson 1355536e340fSRichard Henderson /* 1356536e340fSRichard Henderson * MSR_C and MSR_CC set above. 1357536e340fSRichard Henderson * MSR_PVR is not writable, and is always clear. 1358536e340fSRichard Henderson */ 1359536e340fSRichard Henderson imm &= ~(MSR_C | MSR_CC | MSR_PVR); 1360536e340fSRichard Henderson 1361536e340fSRichard Henderson if (imm != 0) { 1362536e340fSRichard Henderson if (set) { 1363536e340fSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, imm); 1364536e340fSRichard Henderson } else { 1365536e340fSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm); 1366536e340fSRichard Henderson } 136743b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1368536e340fSRichard Henderson } 1369536e340fSRichard Henderson return true; 1370536e340fSRichard Henderson } 1371536e340fSRichard Henderson 1372536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg) 1373536e340fSRichard Henderson { 1374536e340fSRichard Henderson return do_msrclrset(dc, arg, false); 1375536e340fSRichard Henderson } 1376536e340fSRichard Henderson 1377536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) 1378536e340fSRichard Henderson { 1379536e340fSRichard Henderson return do_msrclrset(dc, arg, true); 1380536e340fSRichard Henderson } 1381536e340fSRichard Henderson 13829df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg) 1383fcf5ef2aSThomas Huth { 13849df297a2SRichard Henderson if (trap_userspace(dc, true)) { 13859df297a2SRichard Henderson return true; 1386f0f7e7f7SEdgar E. Iglesias } 1387f0f7e7f7SEdgar E. Iglesias 13889df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY 13899df297a2SRichard Henderson g_assert_not_reached(); 13909df297a2SRichard Henderson #else 13919df297a2SRichard Henderson if (arg->e && arg->rs != 0x1003) { 13929df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 13939df297a2SRichard Henderson "Invalid extended mts reg 0x%x\n", arg->rs); 13949df297a2SRichard Henderson return true; 13952023e9a3SEdgar E. Iglesias } 1396fcf5ef2aSThomas Huth 13979df297a2SRichard Henderson TCGv_i32 src = reg_for_read(dc, arg->ra); 13989df297a2SRichard Henderson switch (arg->rs) { 1399aa28e6d4SRichard Henderson case SR_MSR: 140043b34134SRichard Henderson /* Install MSR_C. */ 140143b34134SRichard Henderson tcg_gen_extract_i32(cpu_msr_c, src, 2, 1); 140243b34134SRichard Henderson /* 140343b34134SRichard Henderson * Clear MSR_C and MSR_CC; 140443b34134SRichard Henderson * MSR_PVR is not writable, and is always clear. 140543b34134SRichard Henderson */ 140643b34134SRichard Henderson tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR)); 1407fcf5ef2aSThomas Huth break; 14089df297a2SRichard Henderson case SR_FSR: 14099df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); 14109df297a2SRichard Henderson break; 14119df297a2SRichard Henderson case 0x800: 14129df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr)); 14139df297a2SRichard Henderson break; 14149df297a2SRichard Henderson case 0x802: 14159df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr)); 14169df297a2SRichard Henderson break; 14179df297a2SRichard Henderson 14189df297a2SRichard Henderson case 0x1000: /* PID */ 14199df297a2SRichard Henderson case 0x1001: /* ZPR */ 14209df297a2SRichard Henderson case 0x1002: /* TLBX */ 14219df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14229df297a2SRichard Henderson case 0x1004: /* TLBHI */ 14239df297a2SRichard Henderson case 0x1005: /* TLBSX */ 14249df297a2SRichard Henderson { 14259df297a2SRichard Henderson TCGv_i32 tmp_ext = tcg_const_i32(arg->e); 14269df297a2SRichard Henderson TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); 14279df297a2SRichard Henderson 14289df297a2SRichard Henderson gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src); 14299df297a2SRichard Henderson tcg_temp_free_i32(tmp_reg); 14309df297a2SRichard Henderson tcg_temp_free_i32(tmp_ext); 14319df297a2SRichard Henderson } 14329df297a2SRichard Henderson break; 14339df297a2SRichard Henderson 14349df297a2SRichard Henderson default: 14359df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs); 14369df297a2SRichard Henderson return true; 14379df297a2SRichard Henderson } 143843b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 14399df297a2SRichard Henderson return true; 14409df297a2SRichard Henderson #endif 14419df297a2SRichard Henderson } 14429df297a2SRichard Henderson 14439df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg) 14449df297a2SRichard Henderson { 14459df297a2SRichard Henderson TCGv_i32 dest = reg_for_write(dc, arg->rd); 14469df297a2SRichard Henderson 14479df297a2SRichard Henderson if (arg->e) { 14489df297a2SRichard Henderson switch (arg->rs) { 1449351527b7SEdgar E. Iglesias case SR_EAR: 1450dbdb77c4SRichard Henderson { 1451dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 14529df297a2SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14539df297a2SRichard Henderson tcg_gen_extrh_i64_i32(dest, t64); 1454dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1455dbdb77c4SRichard Henderson } 14569df297a2SRichard Henderson return true; 14579df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14589df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14599df297a2SRichard Henderson /* Handled below. */ 1460aa28e6d4SRichard Henderson break; 14619df297a2SRichard Henderson #endif 14629df297a2SRichard Henderson case 0x2006 ... 0x2009: 14639df297a2SRichard Henderson /* High bits of PVR6-9 not implemented. */ 14649df297a2SRichard Henderson tcg_gen_movi_i32(dest, 0); 14659df297a2SRichard Henderson return true; 1466fcf5ef2aSThomas Huth default: 14679df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 14689df297a2SRichard Henderson "Invalid extended mfs reg 0x%x\n", arg->rs); 14699df297a2SRichard Henderson return true; 1470fcf5ef2aSThomas Huth } 14719df297a2SRichard Henderson } 14729df297a2SRichard Henderson 14739df297a2SRichard Henderson switch (arg->rs) { 1474aa28e6d4SRichard Henderson case SR_PC: 14759df297a2SRichard Henderson tcg_gen_movi_i32(dest, dc->base.pc_next); 1476fcf5ef2aSThomas Huth break; 1477aa28e6d4SRichard Henderson case SR_MSR: 14789df297a2SRichard Henderson msr_read(dc, dest); 1479fcf5ef2aSThomas Huth break; 1480351527b7SEdgar E. Iglesias case SR_EAR: 1481dbdb77c4SRichard Henderson { 1482dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1483dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14849df297a2SRichard Henderson tcg_gen_extrl_i64_i32(dest, t64); 1485dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1486a1b48e3aSEdgar E. Iglesias } 1487aa28e6d4SRichard Henderson break; 1488351527b7SEdgar E. Iglesias case SR_ESR: 14899df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr)); 1490aa28e6d4SRichard Henderson break; 1491351527b7SEdgar E. Iglesias case SR_FSR: 14929df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr)); 1493aa28e6d4SRichard Henderson break; 1494351527b7SEdgar E. Iglesias case SR_BTR: 14959df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr)); 1496aa28e6d4SRichard Henderson break; 14977cdae31dSTong Ho case SR_EDR: 14989df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr)); 1499fcf5ef2aSThomas Huth break; 1500fcf5ef2aSThomas Huth case 0x800: 15019df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr)); 1502fcf5ef2aSThomas Huth break; 1503fcf5ef2aSThomas Huth case 0x802: 15049df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr)); 1505fcf5ef2aSThomas Huth break; 15069df297a2SRichard Henderson 15079df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 15089df297a2SRichard Henderson case 0x1000: /* PID */ 15099df297a2SRichard Henderson case 0x1001: /* ZPR */ 15109df297a2SRichard Henderson case 0x1002: /* TLBX */ 15119df297a2SRichard Henderson case 0x1003: /* TLBLO */ 15129df297a2SRichard Henderson case 0x1004: /* TLBHI */ 15139df297a2SRichard Henderson case 0x1005: /* TLBSX */ 15149df297a2SRichard Henderson { 15159df297a2SRichard Henderson TCGv_i32 tmp_ext = tcg_const_i32(arg->e); 15169df297a2SRichard Henderson TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); 15179df297a2SRichard Henderson 15189df297a2SRichard Henderson gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg); 15199df297a2SRichard Henderson tcg_temp_free_i32(tmp_reg); 15209df297a2SRichard Henderson tcg_temp_free_i32(tmp_ext); 15219df297a2SRichard Henderson } 15229df297a2SRichard Henderson break; 15239df297a2SRichard Henderson #endif 15249df297a2SRichard Henderson 1525351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 15269df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, 1527a4bcfc33SRichard Henderson offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000]) 1528a4bcfc33SRichard Henderson - offsetof(MicroBlazeCPU, env)); 1529fcf5ef2aSThomas Huth break; 1530fcf5ef2aSThomas Huth default: 15319df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs); 1532fcf5ef2aSThomas Huth break; 1533fcf5ef2aSThomas Huth } 15349df297a2SRichard Henderson return true; 1535fcf5ef2aSThomas Huth } 1536fcf5ef2aSThomas Huth 15373fb394fdSRichard Henderson static void do_rti(DisasContext *dc) 1538fcf5ef2aSThomas Huth { 15393fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1540fcf5ef2aSThomas Huth 15413fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15423fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE); 15433fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM); 15443fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM)); 15453fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 15463fb394fdSRichard Henderson 15473fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1548fcf5ef2aSThomas Huth } 1549fcf5ef2aSThomas Huth 15503fb394fdSRichard Henderson static void do_rtb(DisasContext *dc) 1551fcf5ef2aSThomas Huth { 15523fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1553fcf5ef2aSThomas Huth 15543fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15553fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP)); 15563fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15573fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 15583fb394fdSRichard Henderson 15593fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1560fcf5ef2aSThomas Huth } 1561fcf5ef2aSThomas Huth 15623fb394fdSRichard Henderson static void do_rte(DisasContext *dc) 1563fcf5ef2aSThomas Huth { 15643fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1565fcf5ef2aSThomas Huth 15663fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15673fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE); 15683fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15693fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP)); 15703fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1571fcf5ef2aSThomas Huth 15723fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1573fcf5ef2aSThomas Huth } 1574fcf5ef2aSThomas Huth 1575fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 157652065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl) 1577fcf5ef2aSThomas Huth { 1578fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1579fcf5ef2aSThomas Huth 1580bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 158152065d8fSRichard Henderson return true; 1582fcf5ef2aSThomas Huth } 1583fcf5ef2aSThomas Huth 1584cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 158552065d8fSRichard Henderson if (rb) { 158652065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 1587fcf5ef2aSThomas Huth } else { 158852065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 1589fcf5ef2aSThomas Huth } 1590fcf5ef2aSThomas Huth 1591cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 159252065d8fSRichard Henderson gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl); 1593cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1594cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 159552065d8fSRichard Henderson return true; 159652065d8fSRichard Henderson } 159752065d8fSRichard Henderson 159852065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg) 159952065d8fSRichard Henderson { 160052065d8fSRichard Henderson return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl); 160152065d8fSRichard Henderson } 160252065d8fSRichard Henderson 160352065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg) 160452065d8fSRichard Henderson { 160552065d8fSRichard Henderson return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl); 160652065d8fSRichard Henderson } 160752065d8fSRichard Henderson 160852065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl) 160952065d8fSRichard Henderson { 161052065d8fSRichard Henderson TCGv_i32 t_id, t_ctrl; 161152065d8fSRichard Henderson 161252065d8fSRichard Henderson if (trap_userspace(dc, true)) { 161352065d8fSRichard Henderson return true; 161452065d8fSRichard Henderson } 161552065d8fSRichard Henderson 161652065d8fSRichard Henderson t_id = tcg_temp_new_i32(); 161752065d8fSRichard Henderson if (rb) { 161852065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 161952065d8fSRichard Henderson } else { 162052065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 162152065d8fSRichard Henderson } 162252065d8fSRichard Henderson 162352065d8fSRichard Henderson t_ctrl = tcg_const_i32(ctrl); 162452065d8fSRichard Henderson gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra)); 162552065d8fSRichard Henderson tcg_temp_free_i32(t_id); 162652065d8fSRichard Henderson tcg_temp_free_i32(t_ctrl); 162752065d8fSRichard Henderson return true; 162852065d8fSRichard Henderson } 162952065d8fSRichard Henderson 163052065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg) 163152065d8fSRichard Henderson { 163252065d8fSRichard Henderson return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl); 163352065d8fSRichard Henderson } 163452065d8fSRichard Henderson 163552065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg) 163652065d8fSRichard Henderson { 163752065d8fSRichard Henderson return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); 1638fcf5ef2aSThomas Huth } 1639fcf5ef2aSThomas Huth 1640372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1641fcf5ef2aSThomas Huth { 1642372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1643372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1644372122e3SRichard Henderson int bound; 1645fcf5ef2aSThomas Huth 16464b893631SRichard Henderson dc->cfg = &cpu->cfg; 1647683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags; 1648d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 164920800179SRichard Henderson dc->r0 = NULL; 165020800179SRichard Henderson dc->r0_set = false; 1651287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 1652b9c58aabSRichard Henderson dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; 1653b9c58aabSRichard Henderson dc->jmp_dest = -1; 1654fcf5ef2aSThomas Huth 1655372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1656372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1657fcf5ef2aSThomas Huth } 1658fcf5ef2aSThomas Huth 1659372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1660fcf5ef2aSThomas Huth { 1661fcf5ef2aSThomas Huth } 1662fcf5ef2aSThomas Huth 1663372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1664372122e3SRichard Henderson { 1665683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1666683a247eSRichard Henderson 1667683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); 1668683a247eSRichard Henderson dc->insn_start = tcg_last_op(); 1669372122e3SRichard Henderson } 1670fcf5ef2aSThomas Huth 1671372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1672372122e3SRichard Henderson { 1673372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1674372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 167544d1432bSRichard Henderson uint32_t ir; 1676372122e3SRichard Henderson 1677372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1678372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1679372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1680372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1681fcf5ef2aSThomas Huth } 1682fcf5ef2aSThomas Huth 16836f9642d7SRichard Henderson dc->tb_flags_to_set = 0; 16846f9642d7SRichard Henderson 168544d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 168644d1432bSRichard Henderson if (!decode(dc, ir)) { 1687921afa9dSRichard Henderson trap_illegal(dc, true); 168844d1432bSRichard Henderson } 168920800179SRichard Henderson 169020800179SRichard Henderson if (dc->r0) { 169120800179SRichard Henderson tcg_temp_free_i32(dc->r0); 169220800179SRichard Henderson dc->r0 = NULL; 169320800179SRichard Henderson dc->r0_set = false; 169420800179SRichard Henderson } 169520800179SRichard Henderson 16966f9642d7SRichard Henderson /* Discard the imm global when its contents cannot be used. */ 16976f9642d7SRichard Henderson if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { 1698d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1699372122e3SRichard Henderson } 17006f9642d7SRichard Henderson 17011e521ce3SRichard Henderson dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG); 17026f9642d7SRichard Henderson dc->tb_flags |= dc->tb_flags_to_set; 1703d4705ae0SRichard Henderson dc->base.pc_next += 4; 1704fcf5ef2aSThomas Huth 1705b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { 17063d35bcc2SRichard Henderson /* 17073d35bcc2SRichard Henderson * Finish any return-from branch. 17083d35bcc2SRichard Henderson */ 17093c745866SRichard Henderson uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); 17103c745866SRichard Henderson if (unlikely(rt_ibe != 0)) { 17113c745866SRichard Henderson dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); 17123c745866SRichard Henderson if (rt_ibe & DRTI_FLAG) { 1713fcf5ef2aSThomas Huth do_rti(dc); 17143c745866SRichard Henderson } else if (rt_ibe & DRTB_FLAG) { 1715fcf5ef2aSThomas Huth do_rtb(dc); 17163c745866SRichard Henderson } else { 1717fcf5ef2aSThomas Huth do_rte(dc); 1718372122e3SRichard Henderson } 17193c745866SRichard Henderson } 17203d35bcc2SRichard Henderson 17213d35bcc2SRichard Henderson /* Complete the branch, ending the TB. */ 17223d35bcc2SRichard Henderson switch (dc->base.is_jmp) { 17233d35bcc2SRichard Henderson case DISAS_NORETURN: 17243d35bcc2SRichard Henderson /* 17253d35bcc2SRichard Henderson * E.g. illegal insn in a delay slot. We've already exited 17263d35bcc2SRichard Henderson * and will handle D_FLAG in mb_cpu_do_interrupt. 17273d35bcc2SRichard Henderson */ 17283d35bcc2SRichard Henderson break; 17293d35bcc2SRichard Henderson case DISAS_NEXT: 17303c745866SRichard Henderson /* 17313c745866SRichard Henderson * Normal insn a delay slot. 17323c745866SRichard Henderson * However, the return-from-exception type insns should 17333c745866SRichard Henderson * return to the main loop, as they have adjusted MSR. 17343c745866SRichard Henderson */ 17353c745866SRichard Henderson dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP); 17363d35bcc2SRichard Henderson break; 17373d35bcc2SRichard Henderson case DISAS_EXIT_NEXT: 17383d35bcc2SRichard Henderson /* 17393d35bcc2SRichard Henderson * E.g. mts insn in a delay slot. Continue with btarget, 17403d35bcc2SRichard Henderson * but still return to the main loop. 17413d35bcc2SRichard Henderson */ 17423d35bcc2SRichard Henderson dc->base.is_jmp = DISAS_EXIT_JUMP; 17433d35bcc2SRichard Henderson break; 17443d35bcc2SRichard Henderson default: 17453d35bcc2SRichard Henderson g_assert_not_reached(); 17463d35bcc2SRichard Henderson } 1747372122e3SRichard Henderson } 1748372122e3SRichard Henderson } 1749372122e3SRichard Henderson 1750372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1751372122e3SRichard Henderson { 1752372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1753372122e3SRichard Henderson 1754372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1755372122e3SRichard Henderson /* We have already exited the TB. */ 1756372122e3SRichard Henderson return; 1757372122e3SRichard Henderson } 1758372122e3SRichard Henderson 1759372122e3SRichard Henderson t_sync_flags(dc); 1760372122e3SRichard Henderson 1761372122e3SRichard Henderson switch (dc->base.is_jmp) { 1762372122e3SRichard Henderson case DISAS_TOO_MANY: 1763372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1764372122e3SRichard Henderson return; 1765372122e3SRichard Henderson 176617e77796SRichard Henderson case DISAS_EXIT: 1767f6278ca9SRichard Henderson break; 1768f6278ca9SRichard Henderson case DISAS_EXIT_NEXT: 1769f6278ca9SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1770f6278ca9SRichard Henderson break; 1771f6278ca9SRichard Henderson case DISAS_EXIT_JUMP: 1772f6278ca9SRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1773f6278ca9SRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1774f6278ca9SRichard Henderson break; 1775372122e3SRichard Henderson 1776372122e3SRichard Henderson case DISAS_JUMP: 1777fbafb3a4SRichard Henderson if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) { 1778b9c58aabSRichard Henderson /* Direct jump. */ 1779b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1780b9c58aabSRichard Henderson 1781b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_ALWAYS) { 1782b9c58aabSRichard Henderson /* Conditional direct jump. */ 1783b9c58aabSRichard Henderson TCGLabel *taken = gen_new_label(); 1784b9c58aabSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1785b9c58aabSRichard Henderson 1786b9c58aabSRichard Henderson /* 1787b9c58aabSRichard Henderson * Copy bvalue to a temp now, so we can discard bvalue. 1788b9c58aabSRichard Henderson * This can avoid writing bvalue to memory when the 1789b9c58aabSRichard Henderson * delay slot cannot raise an exception. 1790b9c58aabSRichard Henderson */ 1791b9c58aabSRichard Henderson tcg_gen_mov_i32(tmp, cpu_bvalue); 1792b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_bvalue); 1793b9c58aabSRichard Henderson 1794b9c58aabSRichard Henderson tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken); 1795b9c58aabSRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1796b9c58aabSRichard Henderson gen_set_label(taken); 1797b9c58aabSRichard Henderson } 1798b9c58aabSRichard Henderson gen_goto_tb(dc, 0, dc->jmp_dest); 1799b9c58aabSRichard Henderson return; 1800b9c58aabSRichard Henderson } 1801b9c58aabSRichard Henderson 1802fbafb3a4SRichard Henderson /* Indirect jump (or direct jump w/ goto_tb disabled) */ 1803b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1804b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 18054059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr(); 1806372122e3SRichard Henderson return; 1807372122e3SRichard Henderson 1808a2b80dbdSRichard Henderson default: 1809a2b80dbdSRichard Henderson g_assert_not_reached(); 1810fcf5ef2aSThomas Huth } 1811f6278ca9SRichard Henderson 1812f6278ca9SRichard Henderson /* Finish DISAS_EXIT_* */ 1813f6278ca9SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1814f6278ca9SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1815f6278ca9SRichard Henderson } else { 1816f6278ca9SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1817f6278ca9SRichard Henderson } 1818fcf5ef2aSThomas Huth } 1819fcf5ef2aSThomas Huth 1820372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1821372122e3SRichard Henderson { 1822372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1823372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 1824fcf5ef2aSThomas Huth } 1825372122e3SRichard Henderson 1826372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1827372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1828372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1829372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1830372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1831372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1832372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1833372122e3SRichard Henderson }; 1834372122e3SRichard Henderson 1835372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1836372122e3SRichard Henderson { 1837372122e3SRichard Henderson DisasContext dc; 1838372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 1839fcf5ef2aSThomas Huth } 1840fcf5ef2aSThomas Huth 184190c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1842fcf5ef2aSThomas Huth { 1843fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1844fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 18450c3da918SRichard Henderson uint32_t iflags; 1846fcf5ef2aSThomas Huth int i; 1847fcf5ef2aSThomas Huth 18480c3da918SRichard Henderson qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n", 18490c3da918SRichard Henderson env->pc, env->msr, 18502e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18512e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18522e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18532e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18540c3da918SRichard Henderson 18550c3da918SRichard Henderson iflags = env->iflags; 18560c3da918SRichard Henderson qemu_fprintf(f, "iflags: 0x%08x", iflags); 18570c3da918SRichard Henderson if (iflags & IMM_FLAG) { 18580c3da918SRichard Henderson qemu_fprintf(f, " IMM(0x%08x)", env->imm); 18592ead1b18SJoe Komlodi } 18600c3da918SRichard Henderson if (iflags & BIMM_FLAG) { 18610c3da918SRichard Henderson qemu_fprintf(f, " BIMM"); 18620c3da918SRichard Henderson } 18630c3da918SRichard Henderson if (iflags & D_FLAG) { 1864b9c58aabSRichard Henderson qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget); 18650c3da918SRichard Henderson } 18660c3da918SRichard Henderson if (iflags & DRTI_FLAG) { 18670c3da918SRichard Henderson qemu_fprintf(f, " DRTI"); 18680c3da918SRichard Henderson } 18690c3da918SRichard Henderson if (iflags & DRTE_FLAG) { 18700c3da918SRichard Henderson qemu_fprintf(f, " DRTE"); 18710c3da918SRichard Henderson } 18720c3da918SRichard Henderson if (iflags & DRTB_FLAG) { 18730c3da918SRichard Henderson qemu_fprintf(f, " DRTB"); 18740c3da918SRichard Henderson } 18750c3da918SRichard Henderson if (iflags & ESR_ESS_FLAG) { 18760c3da918SRichard Henderson qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK); 18772ead1b18SJoe Komlodi } 1878fcf5ef2aSThomas Huth 18790c3da918SRichard Henderson qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" 188019f27b6cSRichard Henderson "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n", 18810c3da918SRichard Henderson env->esr, env->fsr, env->btr, env->edr, 18820c3da918SRichard Henderson env->ear, env->slr, env->shr); 18830c3da918SRichard Henderson 18840c3da918SRichard Henderson for (i = 0; i < 32; i++) { 18850c3da918SRichard Henderson qemu_fprintf(f, "r%2.2d=%08x%c", 18860c3da918SRichard Henderson i, env->regs[i], i % 4 == 3 ? '\n' : ' '); 18870c3da918SRichard Henderson } 18880c3da918SRichard Henderson qemu_fprintf(f, "\n"); 1889fcf5ef2aSThomas Huth } 1890fcf5ef2aSThomas Huth 1891fcf5ef2aSThomas Huth void mb_tcg_init(void) 1892fcf5ef2aSThomas Huth { 1893480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1894480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1895fcf5ef2aSThomas Huth 1896480d29a8SRichard Henderson static const struct { 1897480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1898480d29a8SRichard Henderson } i32s[] = { 1899e47c2231SRichard Henderson /* 1900e47c2231SRichard Henderson * Note that r0 is handled specially in reg_for_read 1901e47c2231SRichard Henderson * and reg_for_write. Nothing should touch cpu_R[0]. 1902e47c2231SRichard Henderson * Leave that element NULL, which will assert quickly 1903e47c2231SRichard Henderson * inside the tcg generator functions. 1904e47c2231SRichard Henderson */ 1905e47c2231SRichard Henderson R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1906480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1907480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1908480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1909480d29a8SRichard Henderson 1910480d29a8SRichard Henderson SP(pc), 1911480d29a8SRichard Henderson SP(msr), 19121074c0fbSRichard Henderson SP(msr_c), 1913480d29a8SRichard Henderson SP(imm), 1914480d29a8SRichard Henderson SP(iflags), 1915b9c58aabSRichard Henderson SP(bvalue), 1916480d29a8SRichard Henderson SP(btarget), 1917480d29a8SRichard Henderson SP(res_val), 1918480d29a8SRichard Henderson }; 1919480d29a8SRichard Henderson 1920480d29a8SRichard Henderson #undef R 1921480d29a8SRichard Henderson #undef SP 1922480d29a8SRichard Henderson 1923480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1924480d29a8SRichard Henderson *i32s[i].var = 1925480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1926fcf5ef2aSThomas Huth } 192776e8187dSRichard Henderson 1928480d29a8SRichard Henderson cpu_res_addr = 1929480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1930fcf5ef2aSThomas Huth } 1931fcf5ef2aSThomas Huth 1932fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1933fcf5ef2aSThomas Huth target_ulong *data) 1934fcf5ef2aSThomas Huth { 193576e8187dSRichard Henderson env->pc = data[0]; 1936683a247eSRichard Henderson env->iflags = data[1]; 1937fcf5ef2aSThomas Huth } 1938