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 34*d53106c9SRichard Henderson #define HELPER_H "helper.h" 35*d53106c9SRichard Henderson #include "exec/helper-info.c.inc" 36*d53106c9SRichard Henderson #undef HELPER_H 37*d53106c9SRichard Henderson 38fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 39fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 40fcf5ef2aSThomas Huth 4177fc6f5eSLluís Vilanova /* is_jmp field values */ 4277fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 4317e77796SRichard Henderson #define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */ 4477fc6f5eSLluís Vilanova 45f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */ 46f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2 47f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */ 48f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3 49f6278ca9SRichard Henderson 50cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 510f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 523e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 531074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 549b158558SRichard Henderson static TCGv_i32 cpu_imm; 55b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue; 560f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 579b158558SRichard Henderson static TCGv_i32 cpu_iflags; 589b158558SRichard Henderson static TCGv cpu_res_addr; 599b158558SRichard Henderson static TCGv_i32 cpu_res_val; 60fcf5ef2aSThomas Huth 61fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 62fcf5ef2aSThomas Huth 63fcf5ef2aSThomas Huth /* This is the state at translation time. */ 64fcf5ef2aSThomas Huth typedef struct DisasContext { 65d4705ae0SRichard Henderson DisasContextBase base; 664b893631SRichard Henderson const MicroBlazeCPUConfig *cfg; 67fcf5ef2aSThomas Huth 68683a247eSRichard Henderson /* TCG op of the current insn_start. */ 69683a247eSRichard Henderson TCGOp *insn_start; 70683a247eSRichard Henderson 7120800179SRichard Henderson TCGv_i32 r0; 7220800179SRichard Henderson bool r0_set; 7320800179SRichard Henderson 74fcf5ef2aSThomas Huth /* Decoder. */ 75d7ecb757SRichard Henderson uint32_t ext_imm; 76683a247eSRichard Henderson unsigned int tb_flags; 776f9642d7SRichard Henderson unsigned int tb_flags_to_set; 78287b1defSRichard Henderson int mem_index; 79fcf5ef2aSThomas Huth 80b9c58aabSRichard Henderson /* Condition under which to jump, including NEVER and ALWAYS. */ 81b9c58aabSRichard Henderson TCGCond jmp_cond; 82b9c58aabSRichard Henderson 83b9c58aabSRichard Henderson /* Immediate branch-taken destination, or -1 for indirect. */ 84b9c58aabSRichard Henderson uint32_t jmp_dest; 85fcf5ef2aSThomas Huth } DisasContext; 86fcf5ef2aSThomas Huth 8720800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8820800179SRichard Henderson { 8920800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 9020800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 9120800179SRichard Henderson } 9220800179SRichard Henderson return x; 9320800179SRichard Henderson } 9420800179SRichard Henderson 9544d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9644d1432bSRichard Henderson #include "decode-insns.c.inc" 9744d1432bSRichard Henderson 98683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc) 99fcf5ef2aSThomas Huth { 100fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 10188e74b61SRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) { 10288e74b61SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK); 103fcf5ef2aSThomas Huth } 104fcf5ef2aSThomas Huth } 105fcf5ef2aSThomas Huth 10641ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 107fcf5ef2aSThomas Huth { 108a5ea3dd7SRichard Henderson gen_helper_raise_exception(cpu_env, tcg_constant_i32(index)); 109d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 110fcf5ef2aSThomas Huth } 111fcf5ef2aSThomas Huth 11241ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11341ba37c4SRichard Henderson { 11441ba37c4SRichard Henderson t_sync_flags(dc); 115d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 11641ba37c4SRichard Henderson gen_raise_exception(dc, index); 11741ba37c4SRichard Henderson } 11841ba37c4SRichard Henderson 11941ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12041ba37c4SRichard Henderson { 121a5ea3dd7SRichard Henderson TCGv_i32 tmp = tcg_constant_i32(esr_ec); 12241ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 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 { 12966345580SRichard 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); 265a5ea3dd7SRichard Henderson imm = tcg_constant_i32(arg->imm); 26620800179SRichard Henderson 26720800179SRichard Henderson fn(rd, ra, imm); 26820800179SRichard Henderson return true; 26920800179SRichard Henderson } 27020800179SRichard Henderson 27120800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 27220800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 27320800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 27420800179SRichard Henderson 275607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 276607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 2774b893631SRichard Henderson { return dc->cfg->CFG && do_typea(dc, a, SE, FN); } 278607f5767SRichard Henderson 27939cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 28039cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 28139cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 28239cf3864SRichard Henderson 28339cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 28439cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 2854b893631SRichard Henderson { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); } 28639cf3864SRichard Henderson 28720800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 28820800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 28920800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 29020800179SRichard Henderson 29197955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 29297955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 2934b893631SRichard Henderson { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); } 29497955cebSRichard Henderson 29520800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 29620800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29720800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 29820800179SRichard Henderson 299d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 300d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 301d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 302d5aead3dSRichard Henderson 303d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 304d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 305d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 306d5aead3dSRichard Henderson 30720800179SRichard Henderson /* No input carry, but output carry. */ 30820800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 30920800179SRichard Henderson { 310a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0); 31120800179SRichard Henderson 31220800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 31320800179SRichard Henderson } 31420800179SRichard Henderson 31520800179SRichard Henderson /* Input and output carry. */ 31620800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 31720800179SRichard Henderson { 318a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0); 31920800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 32020800179SRichard Henderson 32120800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 32220800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 32320800179SRichard Henderson } 32420800179SRichard Henderson 32520800179SRichard Henderson /* Input carry, but no output carry. */ 32620800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 32720800179SRichard Henderson { 32820800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 32920800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 33020800179SRichard Henderson } 33120800179SRichard Henderson 33220800179SRichard Henderson DO_TYPEA(add, true, gen_add) 33320800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 33420800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 33520800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 33620800179SRichard Henderson 33720800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 33820800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 33920800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 34020800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 34120800179SRichard Henderson 342cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 343cb0a0a4cSRichard Henderson { 344cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 345cb0a0a4cSRichard Henderson } 346cb0a0a4cSRichard Henderson 347cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 348cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 349cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 350cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 351cb0a0a4cSRichard Henderson 352081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 353081d8e02SRichard Henderson { 354081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 355081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 356081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 357081d8e02SRichard Henderson } 358081d8e02SRichard Henderson 359081d8e02SRichard Henderson static void gen_bsrl(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_shr_i32(out, ina, tmp); 364081d8e02SRichard Henderson } 365081d8e02SRichard Henderson 366081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 367081d8e02SRichard Henderson { 368081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 369081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 370081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 371081d8e02SRichard Henderson } 372081d8e02SRichard Henderson 373081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 374081d8e02SRichard Henderson { 375081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 376081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 377081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 378081d8e02SRichard Henderson 379081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 380081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 381081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 382081d8e02SRichard Henderson imm_w, imm_s); 383081d8e02SRichard Henderson } else { 384081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 385081d8e02SRichard Henderson } 386081d8e02SRichard Henderson } 387081d8e02SRichard Henderson 388081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 389081d8e02SRichard Henderson { 390081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 391081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 392081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 393081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 394081d8e02SRichard Henderson 395081d8e02SRichard Henderson if (imm_w < imm_s) { 396081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 397081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 398081d8e02SRichard Henderson imm_w, imm_s); 399081d8e02SRichard Henderson } else { 400081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 401081d8e02SRichard Henderson } 402081d8e02SRichard Henderson } 403081d8e02SRichard Henderson 404081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 405081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 406081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 407081d8e02SRichard Henderson 408081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 409081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 410081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 411081d8e02SRichard Henderson 412081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 413081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 414081d8e02SRichard Henderson 41539cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 41639cf3864SRichard Henderson { 41739cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 41839cf3864SRichard Henderson } 41939cf3864SRichard Henderson 42039cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 42139cf3864SRichard Henderson 42258b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 42358b48b63SRichard Henderson { 42458b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 42558b48b63SRichard Henderson 42658b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 42758b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 42858b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 42958b48b63SRichard Henderson } 43058b48b63SRichard Henderson 43158b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 43258b48b63SRichard Henderson { 43358b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 43458b48b63SRichard Henderson 43558b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 43658b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 43758b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 43858b48b63SRichard Henderson } 43958b48b63SRichard Henderson 44058b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 44158b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 442a2b0b90eSRichard Henderson 443d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 444d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 445d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 446d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 447d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 448d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 449d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 450d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 451d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 452d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 453d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 454d5aead3dSRichard Henderson 455d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 456d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 457d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 458d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 459d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 460d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 461d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 462d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 463d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 464d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 465d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 466d5aead3dSRichard Henderson 467d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 468d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 469d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 470d5aead3dSRichard Henderson 471d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 472d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 473d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 474d5aead3dSRichard Henderson 475d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 476b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 477b1354342SRichard Henderson { 478b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 479b1354342SRichard Henderson } 480b1354342SRichard Henderson 481b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 482b1354342SRichard Henderson { 483b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 484b1354342SRichard Henderson } 485b1354342SRichard Henderson 486b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 487b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 488b1354342SRichard Henderson 489e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 490e64b2e5cSRichard Henderson { 4912a7567a2SRichard Henderson if (invalid_delay_slot(dc, "imm")) { 4922a7567a2SRichard Henderson return true; 4932a7567a2SRichard Henderson } 494e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 495e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 4966f9642d7SRichard Henderson dc->tb_flags_to_set = IMM_FLAG; 497e64b2e5cSRichard Henderson return true; 498e64b2e5cSRichard Henderson } 499e64b2e5cSRichard Henderson 50097955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 50197955cebSRichard Henderson { 50297955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 50397955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 50497955cebSRichard Henderson } 50597955cebSRichard Henderson 50697955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 50797955cebSRichard Henderson { 50897955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 50997955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 51097955cebSRichard Henderson } 51197955cebSRichard Henderson 51297955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 51397955cebSRichard Henderson { 51497955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 51597955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 51697955cebSRichard Henderson } 51797955cebSRichard Henderson 51897955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 51997955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 52097955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 52197955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 52297955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 52397955cebSRichard Henderson 524cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 525cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 526cb0a0a4cSRichard Henderson 527607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 528607f5767SRichard Henderson { 529607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 530607f5767SRichard Henderson } 531607f5767SRichard Henderson 532607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 533607f5767SRichard Henderson { 534607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 535607f5767SRichard Henderson } 536607f5767SRichard Henderson 537607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 538607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 539607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 540607f5767SRichard Henderson 541a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 542a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 543a2b0b90eSRichard Henderson { 544a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 545a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 546a2b0b90eSRichard Henderson } 547a2b0b90eSRichard Henderson 548a2b0b90eSRichard Henderson /* Input and output carry. */ 549a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 550a2b0b90eSRichard Henderson { 551a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0); 552a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 553a2b0b90eSRichard Henderson 554a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 555a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 556a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 557a2b0b90eSRichard Henderson } 558a2b0b90eSRichard Henderson 559a2b0b90eSRichard Henderson /* No input or output carry. */ 560a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 561a2b0b90eSRichard Henderson { 562a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 563a2b0b90eSRichard Henderson } 564a2b0b90eSRichard Henderson 565a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 566a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 567a2b0b90eSRichard Henderson { 568a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 569a2b0b90eSRichard Henderson 570a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 571a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 572a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 573a2b0b90eSRichard Henderson } 574a2b0b90eSRichard Henderson 575a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 576a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 577a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 578a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 579a2b0b90eSRichard Henderson 580a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 581a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 582a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 583a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 584a2b0b90eSRichard Henderson 58539cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 58639cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 58739cf3864SRichard Henderson 58839cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 58939cf3864SRichard Henderson { 59039cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 59139cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 59239cf3864SRichard Henderson } 59339cf3864SRichard Henderson 59439cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 59539cf3864SRichard Henderson { 59639cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 59739cf3864SRichard Henderson 59839cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 59939cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 60039cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 60139cf3864SRichard Henderson } 60239cf3864SRichard Henderson 60339cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 60439cf3864SRichard Henderson { 60539cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 60639cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 60739cf3864SRichard Henderson } 60839cf3864SRichard Henderson 60939cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 61039cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 61139cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 61239cf3864SRichard Henderson 61339cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 61439cf3864SRichard Henderson { 61539cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 61639cf3864SRichard Henderson } 61739cf3864SRichard Henderson 61839cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 61939cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 62039cf3864SRichard Henderson 62139cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 62239cf3864SRichard Henderson { 62339cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 62439cf3864SRichard Henderson trap_userspace(dc, true); 62539cf3864SRichard Henderson return true; 62639cf3864SRichard Henderson } 62739cf3864SRichard Henderson 628cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 629cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 630cb0a0a4cSRichard Henderson 631d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 632d8e59c4aSRichard Henderson { 633d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 634d8e59c4aSRichard Henderson 635d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 636d8e59c4aSRichard Henderson if (ra && rb) { 637d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 638d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 639d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 640d8e59c4aSRichard Henderson } else if (ra) { 641d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 642d8e59c4aSRichard Henderson } else if (rb) { 643d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 644d8e59c4aSRichard Henderson } else { 645d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 646d8e59c4aSRichard Henderson } 647d8e59c4aSRichard Henderson 6484b893631SRichard Henderson if ((ra == 1 || rb == 1) && dc->cfg->stackprot) { 649d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 650d8e59c4aSRichard Henderson } 651d8e59c4aSRichard Henderson return ret; 652d8e59c4aSRichard Henderson } 653d8e59c4aSRichard Henderson 654d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 655d8e59c4aSRichard Henderson { 656d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 657d8e59c4aSRichard Henderson 658d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 659d8e59c4aSRichard Henderson if (ra) { 660d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 661d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 662d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 663d8e59c4aSRichard Henderson } else { 664d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 665d8e59c4aSRichard Henderson } 666d8e59c4aSRichard Henderson 6674b893631SRichard Henderson if (ra == 1 && dc->cfg->stackprot) { 668d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 669d8e59c4aSRichard Henderson } 670d8e59c4aSRichard Henderson return ret; 671d8e59c4aSRichard Henderson } 672d8e59c4aSRichard Henderson 67319f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY 674d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 675d8e59c4aSRichard Henderson { 6764b893631SRichard Henderson int addr_size = dc->cfg->addr_size; 677d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 678d8e59c4aSRichard Henderson 679d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 680d8e59c4aSRichard Henderson if (rb) { 681d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 682d8e59c4aSRichard Henderson } else { 683d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 684d8e59c4aSRichard Henderson } 685d8e59c4aSRichard Henderson } else { 686d8e59c4aSRichard Henderson if (rb) { 687d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 688d8e59c4aSRichard Henderson } else { 689d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 690d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 691d8e59c4aSRichard Henderson } 692d8e59c4aSRichard Henderson if (addr_size < 64) { 693d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 694d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 695d8e59c4aSRichard Henderson } 696d8e59c4aSRichard Henderson } 697d8e59c4aSRichard Henderson return ret; 698d8e59c4aSRichard Henderson } 69919f27b6cSRichard Henderson #endif 700d8e59c4aSRichard Henderson 701b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY 702ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd, 703ab0c8d0fSRichard Henderson MemOp size, bool store) 704ab0c8d0fSRichard Henderson { 705ab0c8d0fSRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); 706ab0c8d0fSRichard Henderson 707ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG; 708ab0c8d0fSRichard Henderson iflags |= rd << 5; 709ab0c8d0fSRichard Henderson iflags |= store * ESR_S; 710ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W; 711ab0c8d0fSRichard Henderson 712ab0c8d0fSRichard Henderson tcg_set_insn_start_param(dc->insn_start, 1, iflags); 713ab0c8d0fSRichard Henderson } 714b414df75SRichard Henderson #endif 715ab0c8d0fSRichard Henderson 716d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 717d8e59c4aSRichard Henderson int mem_index, bool rev) 718d8e59c4aSRichard Henderson { 719d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 720d8e59c4aSRichard Henderson 721d8e59c4aSRichard Henderson /* 722d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 723d8e59c4aSRichard Henderson * 724d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 725d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 726d8e59c4aSRichard Henderson */ 727d8e59c4aSRichard Henderson if (rev) { 728d8e59c4aSRichard Henderson if (size > MO_8) { 729d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 730d8e59c4aSRichard Henderson } 731d8e59c4aSRichard Henderson if (size < MO_32) { 732d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 733d8e59c4aSRichard Henderson } 734d8e59c4aSRichard Henderson } 735d8e59c4aSRichard Henderson 736b414df75SRichard Henderson /* 737b414df75SRichard Henderson * For system mode, enforce alignment if the cpu configuration 738b414df75SRichard Henderson * requires it. For user-mode, the Linux kernel will have fixed up 739b414df75SRichard Henderson * any unaligned access, so emulate that by *not* setting MO_ALIGN. 740b414df75SRichard Henderson */ 741b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY 742ab0c8d0fSRichard Henderson if (size > MO_8 && 743ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 7444b893631SRichard Henderson dc->cfg->unaligned_exceptions) { 745ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false); 746ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 747d8e59c4aSRichard Henderson } 748b414df75SRichard Henderson #endif 749d8e59c4aSRichard Henderson 750ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); 751d8e59c4aSRichard Henderson return true; 752d8e59c4aSRichard Henderson } 753d8e59c4aSRichard Henderson 754d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 755d8e59c4aSRichard Henderson { 756d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 757d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 758d8e59c4aSRichard Henderson } 759d8e59c4aSRichard Henderson 760d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 761d8e59c4aSRichard Henderson { 762d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 763d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 764d8e59c4aSRichard Henderson } 765d8e59c4aSRichard Henderson 766d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 767d8e59c4aSRichard Henderson { 768d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 769d8e59c4aSRichard Henderson return true; 770d8e59c4aSRichard Henderson } 77119f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 77219f27b6cSRichard Henderson return true; 77319f27b6cSRichard Henderson #else 774d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 775d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 77619f27b6cSRichard Henderson #endif 777d8e59c4aSRichard Henderson } 778d8e59c4aSRichard Henderson 779d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 780d8e59c4aSRichard Henderson { 781d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 782d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 783d8e59c4aSRichard Henderson } 784d8e59c4aSRichard Henderson 785d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 786d8e59c4aSRichard Henderson { 787d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 788d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 789d8e59c4aSRichard Henderson } 790d8e59c4aSRichard Henderson 791d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 792d8e59c4aSRichard Henderson { 793d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 794d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 795d8e59c4aSRichard Henderson } 796d8e59c4aSRichard Henderson 797d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 798d8e59c4aSRichard Henderson { 799d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 800d8e59c4aSRichard Henderson return true; 801d8e59c4aSRichard Henderson } 80219f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 80319f27b6cSRichard Henderson return true; 80419f27b6cSRichard Henderson #else 805d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 806d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 80719f27b6cSRichard Henderson #endif 808d8e59c4aSRichard Henderson } 809d8e59c4aSRichard Henderson 810d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 811d8e59c4aSRichard Henderson { 812d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 813d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 814d8e59c4aSRichard Henderson } 815d8e59c4aSRichard Henderson 816d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 817d8e59c4aSRichard Henderson { 818d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 819d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 820d8e59c4aSRichard Henderson } 821d8e59c4aSRichard Henderson 822d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 823d8e59c4aSRichard Henderson { 824d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 825d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 826d8e59c4aSRichard Henderson } 827d8e59c4aSRichard Henderson 828d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 829d8e59c4aSRichard Henderson { 830d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 831d8e59c4aSRichard Henderson return true; 832d8e59c4aSRichard Henderson } 83319f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 83419f27b6cSRichard Henderson return true; 83519f27b6cSRichard Henderson #else 836d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 837d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 83819f27b6cSRichard Henderson #endif 839d8e59c4aSRichard Henderson } 840d8e59c4aSRichard Henderson 841d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg) 842d8e59c4aSRichard Henderson { 843d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 844d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 845d8e59c4aSRichard Henderson } 846d8e59c4aSRichard Henderson 847d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg) 848d8e59c4aSRichard Henderson { 849d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 850d8e59c4aSRichard Henderson 851d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */ 852d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 853d8e59c4aSRichard Henderson 854d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); 855d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 856d8e59c4aSRichard Henderson 857d8e59c4aSRichard Henderson if (arg->rd) { 858d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 859d8e59c4aSRichard Henderson } 860d8e59c4aSRichard Henderson 861d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 862d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 863d8e59c4aSRichard Henderson return true; 864d8e59c4aSRichard Henderson } 865d8e59c4aSRichard Henderson 866d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 867d8e59c4aSRichard Henderson int mem_index, bool rev) 868d8e59c4aSRichard Henderson { 869d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 870d8e59c4aSRichard Henderson 871d8e59c4aSRichard Henderson /* 872d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 873d8e59c4aSRichard Henderson * 874d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 875d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 876d8e59c4aSRichard Henderson */ 877d8e59c4aSRichard Henderson if (rev) { 878d8e59c4aSRichard Henderson if (size > MO_8) { 879d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 880d8e59c4aSRichard Henderson } 881d8e59c4aSRichard Henderson if (size < MO_32) { 882d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 883d8e59c4aSRichard Henderson } 884d8e59c4aSRichard Henderson } 885d8e59c4aSRichard Henderson 886b414df75SRichard Henderson /* 887b414df75SRichard Henderson * For system mode, enforce alignment if the cpu configuration 888b414df75SRichard Henderson * requires it. For user-mode, the Linux kernel will have fixed up 889b414df75SRichard Henderson * any unaligned access, so emulate that by *not* setting MO_ALIGN. 890b414df75SRichard Henderson */ 891b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY 892ab0c8d0fSRichard Henderson if (size > MO_8 && 893ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 8944b893631SRichard Henderson dc->cfg->unaligned_exceptions) { 895ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true); 896ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 897d8e59c4aSRichard Henderson } 898b414df75SRichard Henderson #endif 899d8e59c4aSRichard Henderson 900ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 901d8e59c4aSRichard Henderson return true; 902d8e59c4aSRichard Henderson } 903d8e59c4aSRichard Henderson 904d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 905d8e59c4aSRichard Henderson { 906d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 907d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 908d8e59c4aSRichard Henderson } 909d8e59c4aSRichard Henderson 910d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 911d8e59c4aSRichard Henderson { 912d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 913d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 914d8e59c4aSRichard Henderson } 915d8e59c4aSRichard Henderson 916d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 917d8e59c4aSRichard Henderson { 918d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 919d8e59c4aSRichard Henderson return true; 920d8e59c4aSRichard Henderson } 92119f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 92219f27b6cSRichard Henderson return true; 92319f27b6cSRichard Henderson #else 924d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 925d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 92619f27b6cSRichard Henderson #endif 927d8e59c4aSRichard Henderson } 928d8e59c4aSRichard Henderson 929d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 930d8e59c4aSRichard Henderson { 931d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 932d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 933d8e59c4aSRichard Henderson } 934d8e59c4aSRichard Henderson 935d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg) 936d8e59c4aSRichard Henderson { 937d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 938d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 939d8e59c4aSRichard Henderson } 940d8e59c4aSRichard Henderson 941d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 942d8e59c4aSRichard Henderson { 943d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 944d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 945d8e59c4aSRichard Henderson } 946d8e59c4aSRichard Henderson 947d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 948d8e59c4aSRichard Henderson { 949d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 950d8e59c4aSRichard Henderson return true; 951d8e59c4aSRichard Henderson } 95219f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 95319f27b6cSRichard Henderson return true; 95419f27b6cSRichard Henderson #else 955d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 956d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 95719f27b6cSRichard Henderson #endif 958d8e59c4aSRichard Henderson } 959d8e59c4aSRichard Henderson 960d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 961d8e59c4aSRichard Henderson { 962d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 963d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 964d8e59c4aSRichard Henderson } 965d8e59c4aSRichard Henderson 966d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 967d8e59c4aSRichard Henderson { 968d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 969d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 970d8e59c4aSRichard Henderson } 971d8e59c4aSRichard Henderson 972d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 973d8e59c4aSRichard Henderson { 974d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 975d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 976d8e59c4aSRichard Henderson } 977d8e59c4aSRichard Henderson 978d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 979d8e59c4aSRichard Henderson { 980d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 981d8e59c4aSRichard Henderson return true; 982d8e59c4aSRichard Henderson } 98319f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 98419f27b6cSRichard Henderson return true; 98519f27b6cSRichard Henderson #else 986d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 987d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 98819f27b6cSRichard Henderson #endif 989d8e59c4aSRichard Henderson } 990d8e59c4aSRichard Henderson 991d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 992d8e59c4aSRichard Henderson { 993d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 994d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 995d8e59c4aSRichard Henderson } 996d8e59c4aSRichard Henderson 997d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 998d8e59c4aSRichard Henderson { 999d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1000d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 1001d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 1002d8e59c4aSRichard Henderson TCGv_i32 tval; 1003d8e59c4aSRichard Henderson 1004d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 1005d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1006d8e59c4aSRichard Henderson 1007d8e59c4aSRichard Henderson /* 1008d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 1009d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 1010d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 1011d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 1012d8e59c4aSRichard Henderson */ 1013d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 1014d8e59c4aSRichard Henderson 1015d8e59c4aSRichard Henderson /* 1016d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 1017d8e59c4aSRichard Henderson * the reserved location. 1018d8e59c4aSRichard Henderson */ 1019d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1020d8e59c4aSRichard Henderson 1021d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1022d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1023d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1024d8e59c4aSRichard Henderson 1025d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1026d8e59c4aSRichard Henderson 1027d8e59c4aSRichard Henderson /* Success */ 1028d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1029d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1030d8e59c4aSRichard Henderson 1031d8e59c4aSRichard Henderson /* Failure */ 1032d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1033d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1034d8e59c4aSRichard Henderson 1035d8e59c4aSRichard Henderson gen_set_label(swx_done); 1036d8e59c4aSRichard Henderson 1037d8e59c4aSRichard Henderson /* 1038d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1039d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1040d8e59c4aSRichard Henderson */ 1041d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1042d8e59c4aSRichard Henderson return true; 1043d8e59c4aSRichard Henderson } 1044d8e59c4aSRichard Henderson 104516bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b) 104616bbbbc9SRichard Henderson { 104716bbbbc9SRichard Henderson dc->tb_flags_to_set |= D_FLAG; 104816bbbbc9SRichard Henderson if (type_b && (dc->tb_flags & IMM_FLAG)) { 104916bbbbc9SRichard Henderson dc->tb_flags_to_set |= BIMM_FLAG; 105016bbbbc9SRichard Henderson } 105116bbbbc9SRichard Henderson } 105216bbbbc9SRichard Henderson 105316bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm, 105416bbbbc9SRichard Henderson bool delay, bool abs, int link) 105516bbbbc9SRichard Henderson { 105616bbbbc9SRichard Henderson uint32_t add_pc; 105716bbbbc9SRichard Henderson 10582a7567a2SRichard Henderson if (invalid_delay_slot(dc, "branch")) { 10592a7567a2SRichard Henderson return true; 10602a7567a2SRichard Henderson } 106116bbbbc9SRichard Henderson if (delay) { 106216bbbbc9SRichard Henderson setup_dslot(dc, dest_rb < 0); 106316bbbbc9SRichard Henderson } 106416bbbbc9SRichard Henderson 106516bbbbc9SRichard Henderson if (link) { 106616bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next); 106716bbbbc9SRichard Henderson } 106816bbbbc9SRichard Henderson 106916bbbbc9SRichard Henderson /* Store the branch taken destination into btarget. */ 107016bbbbc9SRichard Henderson add_pc = abs ? 0 : dc->base.pc_next; 107116bbbbc9SRichard Henderson if (dest_rb > 0) { 107216bbbbc9SRichard Henderson dc->jmp_dest = -1; 107316bbbbc9SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc); 107416bbbbc9SRichard Henderson } else { 107516bbbbc9SRichard Henderson dc->jmp_dest = add_pc + dest_imm; 107616bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 107716bbbbc9SRichard Henderson } 107816bbbbc9SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 107916bbbbc9SRichard Henderson return true; 108016bbbbc9SRichard Henderson } 108116bbbbc9SRichard Henderson 108216bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \ 108316bbbbc9SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \ 108416bbbbc9SRichard Henderson { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \ 108516bbbbc9SRichard Henderson static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \ 108616bbbbc9SRichard Henderson { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); } 108716bbbbc9SRichard Henderson 108816bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false) 108916bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false) 109016bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false) 109116bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false) 109216bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true) 109316bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true) 109416bbbbc9SRichard Henderson 1095fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm, 1096fd779113SRichard Henderson TCGCond cond, int ra, bool delay) 1097fd779113SRichard Henderson { 1098fd779113SRichard Henderson TCGv_i32 zero, next; 1099fd779113SRichard Henderson 11002a7567a2SRichard Henderson if (invalid_delay_slot(dc, "bcc")) { 11012a7567a2SRichard Henderson return true; 11022a7567a2SRichard Henderson } 1103fd779113SRichard Henderson if (delay) { 1104fd779113SRichard Henderson setup_dslot(dc, dest_rb < 0); 1105fd779113SRichard Henderson } 1106fd779113SRichard Henderson 1107fd779113SRichard Henderson dc->jmp_cond = cond; 1108fd779113SRichard Henderson 1109fd779113SRichard Henderson /* Cache the condition register in cpu_bvalue across any delay slot. */ 1110fd779113SRichard Henderson tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra)); 1111fd779113SRichard Henderson 1112fd779113SRichard Henderson /* Store the branch taken destination into btarget. */ 1113fd779113SRichard Henderson if (dest_rb > 0) { 1114fd779113SRichard Henderson dc->jmp_dest = -1; 1115fd779113SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next); 1116fd779113SRichard Henderson } else { 1117fd779113SRichard Henderson dc->jmp_dest = dc->base.pc_next + dest_imm; 1118fd779113SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 1119fd779113SRichard Henderson } 1120fd779113SRichard Henderson 1121fd779113SRichard Henderson /* Compute the final destination into btarget. */ 1122a5ea3dd7SRichard Henderson zero = tcg_constant_i32(0); 1123a5ea3dd7SRichard Henderson next = tcg_constant_i32(dc->base.pc_next + (delay + 1) * 4); 1124fd779113SRichard Henderson tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, 1125fd779113SRichard Henderson reg_for_read(dc, ra), zero, 1126fd779113SRichard Henderson cpu_btarget, next); 1127fd779113SRichard Henderson 1128fd779113SRichard Henderson return true; 1129fd779113SRichard Henderson } 1130fd779113SRichard Henderson 1131fd779113SRichard Henderson #define DO_BCC(NAME, COND) \ 1132fd779113SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \ 1133fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \ 1134fd779113SRichard Henderson static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \ 1135fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \ 1136fd779113SRichard Henderson static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \ 1137fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \ 1138fd779113SRichard Henderson static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \ 1139fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); } 1140fd779113SRichard Henderson 1141fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ) 1142fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE) 1143fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT) 1144fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE) 1145fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT) 1146fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE) 1147fd779113SRichard Henderson 1148f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg) 1149f5235314SRichard Henderson { 1150f5235314SRichard Henderson if (trap_userspace(dc, true)) { 1151f5235314SRichard Henderson return true; 1152f5235314SRichard Henderson } 11532a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brk")) { 11542a7567a2SRichard Henderson return true; 11552a7567a2SRichard Henderson } 11562a7567a2SRichard Henderson 1157f5235314SRichard Henderson tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb)); 1158f5235314SRichard Henderson if (arg->rd) { 1159f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1160f5235314SRichard Henderson } 1161f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP); 1162f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1163f5235314SRichard Henderson 116417e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1165f5235314SRichard Henderson return true; 1166f5235314SRichard Henderson } 1167f5235314SRichard Henderson 1168f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) 1169f5235314SRichard Henderson { 1170f5235314SRichard Henderson uint32_t imm = arg->imm; 1171f5235314SRichard Henderson 1172f5235314SRichard Henderson if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) { 1173f5235314SRichard Henderson return true; 1174f5235314SRichard Henderson } 11752a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brki")) { 11762a7567a2SRichard Henderson return true; 11772a7567a2SRichard Henderson } 11782a7567a2SRichard Henderson 1179f5235314SRichard Henderson tcg_gen_movi_i32(cpu_pc, imm); 1180f5235314SRichard Henderson if (arg->rd) { 1181f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1182f5235314SRichard Henderson } 1183f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1184f5235314SRichard Henderson 1185f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY 1186f5235314SRichard Henderson switch (imm) { 1187f5235314SRichard Henderson case 0x8: /* syscall trap */ 1188f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_SYSCALL); 1189f5235314SRichard Henderson break; 1190f5235314SRichard Henderson case 0x18: /* debug trap */ 1191f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1192f5235314SRichard Henderson break; 1193f5235314SRichard Henderson default: /* eliminated with trap_userspace check */ 1194f5235314SRichard Henderson g_assert_not_reached(); 1195f5235314SRichard Henderson } 1196f5235314SRichard Henderson #else 1197f5235314SRichard Henderson uint32_t msr_to_set = 0; 1198f5235314SRichard Henderson 1199f5235314SRichard Henderson if (imm != 0x18) { 1200f5235314SRichard Henderson msr_to_set |= MSR_BIP; 1201f5235314SRichard Henderson } 1202f5235314SRichard Henderson if (imm == 0x8 || imm == 0x18) { 1203f5235314SRichard Henderson /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */ 1204f5235314SRichard Henderson msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1; 1205f5235314SRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, 1206f5235314SRichard Henderson ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM)); 1207f5235314SRichard Henderson } 1208f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set); 120917e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1210f5235314SRichard Henderson #endif 1211f5235314SRichard Henderson 1212f5235314SRichard Henderson return true; 1213f5235314SRichard Henderson } 1214f5235314SRichard Henderson 1215ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg) 1216ee8c7f9fSRichard Henderson { 1217ee8c7f9fSRichard Henderson int mbar_imm = arg->imm; 1218ee8c7f9fSRichard Henderson 12192a7567a2SRichard Henderson /* Note that mbar is a specialized branch instruction. */ 12202a7567a2SRichard Henderson if (invalid_delay_slot(dc, "mbar")) { 12212a7567a2SRichard Henderson return true; 12222a7567a2SRichard Henderson } 12232a7567a2SRichard Henderson 1224ee8c7f9fSRichard Henderson /* Data access memory barrier. */ 1225ee8c7f9fSRichard Henderson if ((mbar_imm & 2) == 0) { 1226ee8c7f9fSRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 1227ee8c7f9fSRichard Henderson } 1228ee8c7f9fSRichard Henderson 1229ee8c7f9fSRichard Henderson /* Sleep. */ 1230ee8c7f9fSRichard Henderson if (mbar_imm & 16) { 1231ee8c7f9fSRichard Henderson if (trap_userspace(dc, true)) { 1232ee8c7f9fSRichard Henderson /* Sleep is a privileged instruction. */ 1233ee8c7f9fSRichard Henderson return true; 1234ee8c7f9fSRichard Henderson } 1235ee8c7f9fSRichard Henderson 1236ee8c7f9fSRichard Henderson t_sync_flags(dc); 1237ee8c7f9fSRichard Henderson 1238a5ea3dd7SRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, 1239ee8c7f9fSRichard Henderson -offsetof(MicroBlazeCPU, env) 1240ee8c7f9fSRichard Henderson +offsetof(CPUState, halted)); 1241ee8c7f9fSRichard Henderson 1242ee8c7f9fSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1243ee8c7f9fSRichard Henderson 1244ee8c7f9fSRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1245ee8c7f9fSRichard Henderson } 1246ee8c7f9fSRichard Henderson 1247ee8c7f9fSRichard Henderson /* 1248ee8c7f9fSRichard Henderson * If !(mbar_imm & 1), this is an instruction access memory barrier 1249ee8c7f9fSRichard Henderson * and we need to end the TB so that we recognize self-modified 1250ee8c7f9fSRichard Henderson * code immediately. 1251ee8c7f9fSRichard Henderson * 1252ee8c7f9fSRichard Henderson * However, there are some data mbars that need the TB break 1253ee8c7f9fSRichard Henderson * (and return to main loop) to recognize interrupts right away. 1254ee8c7f9fSRichard Henderson * E.g. recognizing a change to an interrupt controller register. 1255ee8c7f9fSRichard Henderson * 1256ee8c7f9fSRichard Henderson * Therefore, choose to end the TB always. 1257ee8c7f9fSRichard Henderson */ 125843b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1259ee8c7f9fSRichard Henderson return true; 1260ee8c7f9fSRichard Henderson } 1261ee8c7f9fSRichard Henderson 1262e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set) 1263e6cb0354SRichard Henderson { 1264e6cb0354SRichard Henderson if (trap_userspace(dc, to_set)) { 1265e6cb0354SRichard Henderson return true; 1266e6cb0354SRichard Henderson } 12672a7567a2SRichard Henderson if (invalid_delay_slot(dc, "rts")) { 12682a7567a2SRichard Henderson return true; 12692a7567a2SRichard Henderson } 12702a7567a2SRichard Henderson 1271e6cb0354SRichard Henderson dc->tb_flags_to_set |= to_set; 1272e6cb0354SRichard Henderson setup_dslot(dc, true); 1273e6cb0354SRichard Henderson 1274e6cb0354SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 1275e6cb0354SRichard Henderson dc->jmp_dest = -1; 1276e6cb0354SRichard Henderson tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm); 1277e6cb0354SRichard Henderson return true; 1278e6cb0354SRichard Henderson } 1279e6cb0354SRichard Henderson 1280e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \ 1281e6cb0354SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \ 1282e6cb0354SRichard Henderson { return do_rts(dc, arg, IFLAG); } 1283e6cb0354SRichard Henderson 1284e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG) 1285e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG) 1286e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG) 1287e6cb0354SRichard Henderson DO_RTS(rtsd, 0) 1288e6cb0354SRichard Henderson 128920800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 129020800179SRichard Henderson { 129120800179SRichard Henderson /* If opcode_0_illegal, trap. */ 12924b893631SRichard Henderson if (dc->cfg->opcode_0_illegal) { 129320800179SRichard Henderson trap_illegal(dc, true); 129420800179SRichard Henderson return true; 129520800179SRichard Henderson } 129620800179SRichard Henderson /* 129720800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 129820800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 129920800179SRichard Henderson */ 130020800179SRichard Henderson return false; 1301fcf5ef2aSThomas Huth } 1302fcf5ef2aSThomas Huth 13031074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 1304fcf5ef2aSThomas Huth { 13051074c0fbSRichard Henderson TCGv_i32 t; 13061074c0fbSRichard Henderson 13071074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 13081074c0fbSRichard Henderson t = tcg_temp_new_i32(); 13091074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 13101074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 1311fcf5ef2aSThomas Huth } 1312fcf5ef2aSThomas Huth 1313536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) 1314536e340fSRichard Henderson { 1315536e340fSRichard Henderson uint32_t imm = arg->imm; 1316536e340fSRichard Henderson 1317536e340fSRichard Henderson if (trap_userspace(dc, imm != MSR_C)) { 1318536e340fSRichard Henderson return true; 1319536e340fSRichard Henderson } 1320536e340fSRichard Henderson 1321536e340fSRichard Henderson if (arg->rd) { 1322536e340fSRichard Henderson msr_read(dc, cpu_R[arg->rd]); 1323536e340fSRichard Henderson } 1324536e340fSRichard Henderson 1325536e340fSRichard Henderson /* 1326536e340fSRichard Henderson * Handle the carry bit separately. 1327536e340fSRichard Henderson * This is the only bit that userspace can modify. 1328536e340fSRichard Henderson */ 1329536e340fSRichard Henderson if (imm & MSR_C) { 1330536e340fSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, set); 1331536e340fSRichard Henderson } 1332536e340fSRichard Henderson 1333536e340fSRichard Henderson /* 1334536e340fSRichard Henderson * MSR_C and MSR_CC set above. 1335536e340fSRichard Henderson * MSR_PVR is not writable, and is always clear. 1336536e340fSRichard Henderson */ 1337536e340fSRichard Henderson imm &= ~(MSR_C | MSR_CC | MSR_PVR); 1338536e340fSRichard Henderson 1339536e340fSRichard Henderson if (imm != 0) { 1340536e340fSRichard Henderson if (set) { 1341536e340fSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, imm); 1342536e340fSRichard Henderson } else { 1343536e340fSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm); 1344536e340fSRichard Henderson } 134543b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1346536e340fSRichard Henderson } 1347536e340fSRichard Henderson return true; 1348536e340fSRichard Henderson } 1349536e340fSRichard Henderson 1350536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg) 1351536e340fSRichard Henderson { 1352536e340fSRichard Henderson return do_msrclrset(dc, arg, false); 1353536e340fSRichard Henderson } 1354536e340fSRichard Henderson 1355536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) 1356536e340fSRichard Henderson { 1357536e340fSRichard Henderson return do_msrclrset(dc, arg, true); 1358536e340fSRichard Henderson } 1359536e340fSRichard Henderson 13609df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg) 1361fcf5ef2aSThomas Huth { 13629df297a2SRichard Henderson if (trap_userspace(dc, true)) { 13639df297a2SRichard Henderson return true; 1364f0f7e7f7SEdgar E. Iglesias } 1365f0f7e7f7SEdgar E. Iglesias 13669df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY 13679df297a2SRichard Henderson g_assert_not_reached(); 13689df297a2SRichard Henderson #else 13699df297a2SRichard Henderson if (arg->e && arg->rs != 0x1003) { 13709df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 13719df297a2SRichard Henderson "Invalid extended mts reg 0x%x\n", arg->rs); 13729df297a2SRichard Henderson return true; 13732023e9a3SEdgar E. Iglesias } 1374fcf5ef2aSThomas Huth 13759df297a2SRichard Henderson TCGv_i32 src = reg_for_read(dc, arg->ra); 13769df297a2SRichard Henderson switch (arg->rs) { 1377aa28e6d4SRichard Henderson case SR_MSR: 137843b34134SRichard Henderson /* Install MSR_C. */ 137943b34134SRichard Henderson tcg_gen_extract_i32(cpu_msr_c, src, 2, 1); 138043b34134SRichard Henderson /* 138143b34134SRichard Henderson * Clear MSR_C and MSR_CC; 138243b34134SRichard Henderson * MSR_PVR is not writable, and is always clear. 138343b34134SRichard Henderson */ 138443b34134SRichard Henderson tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR)); 1385fcf5ef2aSThomas Huth break; 13869df297a2SRichard Henderson case SR_FSR: 13879df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); 13889df297a2SRichard Henderson break; 13899df297a2SRichard Henderson case 0x800: 13909df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr)); 13919df297a2SRichard Henderson break; 13929df297a2SRichard Henderson case 0x802: 13939df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr)); 13949df297a2SRichard Henderson break; 13959df297a2SRichard Henderson 13969df297a2SRichard Henderson case 0x1000: /* PID */ 13979df297a2SRichard Henderson case 0x1001: /* ZPR */ 13989df297a2SRichard Henderson case 0x1002: /* TLBX */ 13999df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14009df297a2SRichard Henderson case 0x1004: /* TLBHI */ 14019df297a2SRichard Henderson case 0x1005: /* TLBSX */ 14029df297a2SRichard Henderson { 1403a5ea3dd7SRichard Henderson TCGv_i32 tmp_ext = tcg_constant_i32(arg->e); 1404a5ea3dd7SRichard Henderson TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7); 14059df297a2SRichard Henderson 14069df297a2SRichard Henderson gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src); 14079df297a2SRichard Henderson } 14089df297a2SRichard Henderson break; 14099df297a2SRichard Henderson 14109df297a2SRichard Henderson default: 14119df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs); 14129df297a2SRichard Henderson return true; 14139df297a2SRichard Henderson } 141443b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 14159df297a2SRichard Henderson return true; 14169df297a2SRichard Henderson #endif 14179df297a2SRichard Henderson } 14189df297a2SRichard Henderson 14199df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg) 14209df297a2SRichard Henderson { 14219df297a2SRichard Henderson TCGv_i32 dest = reg_for_write(dc, arg->rd); 14229df297a2SRichard Henderson 14239df297a2SRichard Henderson if (arg->e) { 14249df297a2SRichard Henderson switch (arg->rs) { 1425351527b7SEdgar E. Iglesias case SR_EAR: 1426dbdb77c4SRichard Henderson { 1427dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 14289df297a2SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14299df297a2SRichard Henderson tcg_gen_extrh_i64_i32(dest, t64); 1430dbdb77c4SRichard Henderson } 14319df297a2SRichard Henderson return true; 14329df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14339df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14349df297a2SRichard Henderson /* Handled below. */ 1435aa28e6d4SRichard Henderson break; 14369df297a2SRichard Henderson #endif 14379df297a2SRichard Henderson case 0x2006 ... 0x2009: 14389df297a2SRichard Henderson /* High bits of PVR6-9 not implemented. */ 14399df297a2SRichard Henderson tcg_gen_movi_i32(dest, 0); 14409df297a2SRichard Henderson return true; 1441fcf5ef2aSThomas Huth default: 14429df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 14439df297a2SRichard Henderson "Invalid extended mfs reg 0x%x\n", arg->rs); 14449df297a2SRichard Henderson return true; 1445fcf5ef2aSThomas Huth } 14469df297a2SRichard Henderson } 14479df297a2SRichard Henderson 14489df297a2SRichard Henderson switch (arg->rs) { 1449aa28e6d4SRichard Henderson case SR_PC: 14509df297a2SRichard Henderson tcg_gen_movi_i32(dest, dc->base.pc_next); 1451fcf5ef2aSThomas Huth break; 1452aa28e6d4SRichard Henderson case SR_MSR: 14539df297a2SRichard Henderson msr_read(dc, dest); 1454fcf5ef2aSThomas Huth break; 1455351527b7SEdgar E. Iglesias case SR_EAR: 1456dbdb77c4SRichard Henderson { 1457dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1458dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14599df297a2SRichard Henderson tcg_gen_extrl_i64_i32(dest, t64); 1460a1b48e3aSEdgar E. Iglesias } 1461aa28e6d4SRichard Henderson break; 1462351527b7SEdgar E. Iglesias case SR_ESR: 14639df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr)); 1464aa28e6d4SRichard Henderson break; 1465351527b7SEdgar E. Iglesias case SR_FSR: 14669df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr)); 1467aa28e6d4SRichard Henderson break; 1468351527b7SEdgar E. Iglesias case SR_BTR: 14699df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr)); 1470aa28e6d4SRichard Henderson break; 14717cdae31dSTong Ho case SR_EDR: 14729df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr)); 1473fcf5ef2aSThomas Huth break; 1474fcf5ef2aSThomas Huth case 0x800: 14759df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr)); 1476fcf5ef2aSThomas Huth break; 1477fcf5ef2aSThomas Huth case 0x802: 14789df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr)); 1479fcf5ef2aSThomas Huth break; 14809df297a2SRichard Henderson 14819df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14829df297a2SRichard Henderson case 0x1000: /* PID */ 14839df297a2SRichard Henderson case 0x1001: /* ZPR */ 14849df297a2SRichard Henderson case 0x1002: /* TLBX */ 14859df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14869df297a2SRichard Henderson case 0x1004: /* TLBHI */ 14879df297a2SRichard Henderson case 0x1005: /* TLBSX */ 14889df297a2SRichard Henderson { 1489a5ea3dd7SRichard Henderson TCGv_i32 tmp_ext = tcg_constant_i32(arg->e); 1490a5ea3dd7SRichard Henderson TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7); 14919df297a2SRichard Henderson 14929df297a2SRichard Henderson gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg); 14939df297a2SRichard Henderson } 14949df297a2SRichard Henderson break; 14959df297a2SRichard Henderson #endif 14969df297a2SRichard Henderson 1497351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 14989df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, 1499a4bcfc33SRichard Henderson offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000]) 1500a4bcfc33SRichard Henderson - offsetof(MicroBlazeCPU, env)); 1501fcf5ef2aSThomas Huth break; 1502fcf5ef2aSThomas Huth default: 15039df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs); 1504fcf5ef2aSThomas Huth break; 1505fcf5ef2aSThomas Huth } 15069df297a2SRichard Henderson return true; 1507fcf5ef2aSThomas Huth } 1508fcf5ef2aSThomas Huth 15093fb394fdSRichard Henderson static void do_rti(DisasContext *dc) 1510fcf5ef2aSThomas Huth { 15113fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1512fcf5ef2aSThomas Huth 15133fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15143fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE); 15153fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM); 15163fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM)); 15173fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1518fcf5ef2aSThomas Huth } 1519fcf5ef2aSThomas Huth 15203fb394fdSRichard Henderson static void do_rtb(DisasContext *dc) 1521fcf5ef2aSThomas Huth { 15223fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1523fcf5ef2aSThomas Huth 15243fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15253fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP)); 15263fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15273fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1528fcf5ef2aSThomas Huth } 1529fcf5ef2aSThomas Huth 15303fb394fdSRichard Henderson static void do_rte(DisasContext *dc) 1531fcf5ef2aSThomas Huth { 15323fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1533fcf5ef2aSThomas Huth 15343fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15353fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE); 15363fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15373fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP)); 15383fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1539fcf5ef2aSThomas Huth } 1540fcf5ef2aSThomas Huth 1541fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 154252065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl) 1543fcf5ef2aSThomas Huth { 1544fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1545fcf5ef2aSThomas Huth 1546bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 154752065d8fSRichard Henderson return true; 1548fcf5ef2aSThomas Huth } 1549fcf5ef2aSThomas Huth 1550cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 155152065d8fSRichard Henderson if (rb) { 155252065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 1553fcf5ef2aSThomas Huth } else { 155452065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 1555fcf5ef2aSThomas Huth } 1556fcf5ef2aSThomas Huth 1557a5ea3dd7SRichard Henderson t_ctrl = tcg_constant_i32(ctrl); 155852065d8fSRichard Henderson gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl); 155952065d8fSRichard Henderson return true; 156052065d8fSRichard Henderson } 156152065d8fSRichard Henderson 156252065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg) 156352065d8fSRichard Henderson { 156452065d8fSRichard Henderson return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl); 156552065d8fSRichard Henderson } 156652065d8fSRichard Henderson 156752065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg) 156852065d8fSRichard Henderson { 156952065d8fSRichard Henderson return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl); 157052065d8fSRichard Henderson } 157152065d8fSRichard Henderson 157252065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl) 157352065d8fSRichard Henderson { 157452065d8fSRichard Henderson TCGv_i32 t_id, t_ctrl; 157552065d8fSRichard Henderson 157652065d8fSRichard Henderson if (trap_userspace(dc, true)) { 157752065d8fSRichard Henderson return true; 157852065d8fSRichard Henderson } 157952065d8fSRichard Henderson 158052065d8fSRichard Henderson t_id = tcg_temp_new_i32(); 158152065d8fSRichard Henderson if (rb) { 158252065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 158352065d8fSRichard Henderson } else { 158452065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 158552065d8fSRichard Henderson } 158652065d8fSRichard Henderson 1587a5ea3dd7SRichard Henderson t_ctrl = tcg_constant_i32(ctrl); 158852065d8fSRichard Henderson gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra)); 158952065d8fSRichard Henderson return true; 159052065d8fSRichard Henderson } 159152065d8fSRichard Henderson 159252065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg) 159352065d8fSRichard Henderson { 159452065d8fSRichard Henderson return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl); 159552065d8fSRichard Henderson } 159652065d8fSRichard Henderson 159752065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg) 159852065d8fSRichard Henderson { 159952065d8fSRichard Henderson return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); 1600fcf5ef2aSThomas Huth } 1601fcf5ef2aSThomas Huth 1602372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1603fcf5ef2aSThomas Huth { 1604372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1605372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1606372122e3SRichard Henderson int bound; 1607fcf5ef2aSThomas Huth 16084b893631SRichard Henderson dc->cfg = &cpu->cfg; 1609683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags; 1610d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 161120800179SRichard Henderson dc->r0 = NULL; 161220800179SRichard Henderson dc->r0_set = false; 1613287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 1614b9c58aabSRichard Henderson dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; 1615b9c58aabSRichard Henderson dc->jmp_dest = -1; 1616fcf5ef2aSThomas Huth 1617372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1618372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1619fcf5ef2aSThomas Huth } 1620fcf5ef2aSThomas Huth 1621372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1622fcf5ef2aSThomas Huth { 1623fcf5ef2aSThomas Huth } 1624fcf5ef2aSThomas Huth 1625372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1626372122e3SRichard Henderson { 1627683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1628683a247eSRichard Henderson 1629683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); 1630683a247eSRichard Henderson dc->insn_start = tcg_last_op(); 1631372122e3SRichard Henderson } 1632fcf5ef2aSThomas Huth 1633372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1634372122e3SRichard Henderson { 1635372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1636372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 163744d1432bSRichard Henderson uint32_t ir; 1638372122e3SRichard Henderson 1639372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1640372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1641372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1642372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1643fcf5ef2aSThomas Huth } 1644fcf5ef2aSThomas Huth 16456f9642d7SRichard Henderson dc->tb_flags_to_set = 0; 16466f9642d7SRichard Henderson 164744d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 164844d1432bSRichard Henderson if (!decode(dc, ir)) { 1649921afa9dSRichard Henderson trap_illegal(dc, true); 165044d1432bSRichard Henderson } 165120800179SRichard Henderson 165220800179SRichard Henderson if (dc->r0) { 165320800179SRichard Henderson dc->r0 = NULL; 165420800179SRichard Henderson dc->r0_set = false; 165520800179SRichard Henderson } 165620800179SRichard Henderson 16576f9642d7SRichard Henderson /* Discard the imm global when its contents cannot be used. */ 16586f9642d7SRichard Henderson if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { 1659d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1660372122e3SRichard Henderson } 16616f9642d7SRichard Henderson 16621e521ce3SRichard Henderson dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG); 16636f9642d7SRichard Henderson dc->tb_flags |= dc->tb_flags_to_set; 1664d4705ae0SRichard Henderson dc->base.pc_next += 4; 1665fcf5ef2aSThomas Huth 1666b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { 16673d35bcc2SRichard Henderson /* 16683d35bcc2SRichard Henderson * Finish any return-from branch. 16693d35bcc2SRichard Henderson */ 16703c745866SRichard Henderson uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); 16713c745866SRichard Henderson if (unlikely(rt_ibe != 0)) { 16723c745866SRichard Henderson dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); 16733c745866SRichard Henderson if (rt_ibe & DRTI_FLAG) { 1674fcf5ef2aSThomas Huth do_rti(dc); 16753c745866SRichard Henderson } else if (rt_ibe & DRTB_FLAG) { 1676fcf5ef2aSThomas Huth do_rtb(dc); 16773c745866SRichard Henderson } else { 1678fcf5ef2aSThomas Huth do_rte(dc); 1679372122e3SRichard Henderson } 16803c745866SRichard Henderson } 16813d35bcc2SRichard Henderson 16823d35bcc2SRichard Henderson /* Complete the branch, ending the TB. */ 16833d35bcc2SRichard Henderson switch (dc->base.is_jmp) { 16843d35bcc2SRichard Henderson case DISAS_NORETURN: 16853d35bcc2SRichard Henderson /* 16863d35bcc2SRichard Henderson * E.g. illegal insn in a delay slot. We've already exited 16873d35bcc2SRichard Henderson * and will handle D_FLAG in mb_cpu_do_interrupt. 16883d35bcc2SRichard Henderson */ 16893d35bcc2SRichard Henderson break; 16903d35bcc2SRichard Henderson case DISAS_NEXT: 16913c745866SRichard Henderson /* 16923c745866SRichard Henderson * Normal insn a delay slot. 16933c745866SRichard Henderson * However, the return-from-exception type insns should 16943c745866SRichard Henderson * return to the main loop, as they have adjusted MSR. 16953c745866SRichard Henderson */ 16963c745866SRichard Henderson dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP); 16973d35bcc2SRichard Henderson break; 16983d35bcc2SRichard Henderson case DISAS_EXIT_NEXT: 16993d35bcc2SRichard Henderson /* 17003d35bcc2SRichard Henderson * E.g. mts insn in a delay slot. Continue with btarget, 17013d35bcc2SRichard Henderson * but still return to the main loop. 17023d35bcc2SRichard Henderson */ 17033d35bcc2SRichard Henderson dc->base.is_jmp = DISAS_EXIT_JUMP; 17043d35bcc2SRichard Henderson break; 17053d35bcc2SRichard Henderson default: 17063d35bcc2SRichard Henderson g_assert_not_reached(); 17073d35bcc2SRichard Henderson } 1708372122e3SRichard Henderson } 1709372122e3SRichard Henderson } 1710372122e3SRichard Henderson 1711372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1712372122e3SRichard Henderson { 1713372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1714372122e3SRichard Henderson 1715372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1716372122e3SRichard Henderson /* We have already exited the TB. */ 1717372122e3SRichard Henderson return; 1718372122e3SRichard Henderson } 1719372122e3SRichard Henderson 1720372122e3SRichard Henderson t_sync_flags(dc); 1721372122e3SRichard Henderson 1722372122e3SRichard Henderson switch (dc->base.is_jmp) { 1723372122e3SRichard Henderson case DISAS_TOO_MANY: 1724372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1725372122e3SRichard Henderson return; 1726372122e3SRichard Henderson 172717e77796SRichard Henderson case DISAS_EXIT: 1728f6278ca9SRichard Henderson break; 1729f6278ca9SRichard Henderson case DISAS_EXIT_NEXT: 1730f6278ca9SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1731f6278ca9SRichard Henderson break; 1732f6278ca9SRichard Henderson case DISAS_EXIT_JUMP: 1733f6278ca9SRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1734f6278ca9SRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1735f6278ca9SRichard Henderson break; 1736372122e3SRichard Henderson 1737372122e3SRichard Henderson case DISAS_JUMP: 1738fbafb3a4SRichard Henderson if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) { 1739b9c58aabSRichard Henderson /* Direct jump. */ 1740b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1741b9c58aabSRichard Henderson 1742b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_ALWAYS) { 1743b9c58aabSRichard Henderson /* Conditional direct jump. */ 1744b9c58aabSRichard Henderson TCGLabel *taken = gen_new_label(); 1745b9c58aabSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1746b9c58aabSRichard Henderson 1747b9c58aabSRichard Henderson /* 1748b9c58aabSRichard Henderson * Copy bvalue to a temp now, so we can discard bvalue. 1749b9c58aabSRichard Henderson * This can avoid writing bvalue to memory when the 1750b9c58aabSRichard Henderson * delay slot cannot raise an exception. 1751b9c58aabSRichard Henderson */ 1752b9c58aabSRichard Henderson tcg_gen_mov_i32(tmp, cpu_bvalue); 1753b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_bvalue); 1754b9c58aabSRichard Henderson 1755b9c58aabSRichard Henderson tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken); 1756b9c58aabSRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1757b9c58aabSRichard Henderson gen_set_label(taken); 1758b9c58aabSRichard Henderson } 1759b9c58aabSRichard Henderson gen_goto_tb(dc, 0, dc->jmp_dest); 1760b9c58aabSRichard Henderson return; 1761b9c58aabSRichard Henderson } 1762b9c58aabSRichard Henderson 1763fbafb3a4SRichard Henderson /* Indirect jump (or direct jump w/ goto_tb disabled) */ 1764b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1765b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 17664059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr(); 1767372122e3SRichard Henderson return; 1768372122e3SRichard Henderson 1769a2b80dbdSRichard Henderson default: 1770a2b80dbdSRichard Henderson g_assert_not_reached(); 1771fcf5ef2aSThomas Huth } 1772f6278ca9SRichard Henderson 1773f6278ca9SRichard Henderson /* Finish DISAS_EXIT_* */ 1774f6278ca9SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1775f6278ca9SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1776f6278ca9SRichard Henderson } else { 1777f6278ca9SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1778f6278ca9SRichard Henderson } 1779fcf5ef2aSThomas Huth } 1780fcf5ef2aSThomas Huth 17818eb806a7SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, 17828eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 1783372122e3SRichard Henderson { 17848eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(dcb->pc_first)); 17858eb806a7SRichard Henderson target_disas(logfile, cs, dcb->pc_first, dcb->tb->size); 1786fcf5ef2aSThomas Huth } 1787372122e3SRichard Henderson 1788372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1789372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1790372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1791372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1792372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1793372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1794372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1795372122e3SRichard Henderson }; 1796372122e3SRichard Henderson 1797597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, 1798306c8721SRichard Henderson target_ulong pc, void *host_pc) 1799372122e3SRichard Henderson { 1800372122e3SRichard Henderson DisasContext dc; 1801306c8721SRichard Henderson translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base); 1802fcf5ef2aSThomas Huth } 1803fcf5ef2aSThomas Huth 180490c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1805fcf5ef2aSThomas Huth { 1806fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1807fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 18080c3da918SRichard Henderson uint32_t iflags; 1809fcf5ef2aSThomas Huth int i; 1810fcf5ef2aSThomas Huth 18110c3da918SRichard Henderson qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n", 18120c3da918SRichard Henderson env->pc, env->msr, 18132e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18142e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18152e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18162e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18170c3da918SRichard Henderson 18180c3da918SRichard Henderson iflags = env->iflags; 18190c3da918SRichard Henderson qemu_fprintf(f, "iflags: 0x%08x", iflags); 18200c3da918SRichard Henderson if (iflags & IMM_FLAG) { 18210c3da918SRichard Henderson qemu_fprintf(f, " IMM(0x%08x)", env->imm); 18222ead1b18SJoe Komlodi } 18230c3da918SRichard Henderson if (iflags & BIMM_FLAG) { 18240c3da918SRichard Henderson qemu_fprintf(f, " BIMM"); 18250c3da918SRichard Henderson } 18260c3da918SRichard Henderson if (iflags & D_FLAG) { 1827b9c58aabSRichard Henderson qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget); 18280c3da918SRichard Henderson } 18290c3da918SRichard Henderson if (iflags & DRTI_FLAG) { 18300c3da918SRichard Henderson qemu_fprintf(f, " DRTI"); 18310c3da918SRichard Henderson } 18320c3da918SRichard Henderson if (iflags & DRTE_FLAG) { 18330c3da918SRichard Henderson qemu_fprintf(f, " DRTE"); 18340c3da918SRichard Henderson } 18350c3da918SRichard Henderson if (iflags & DRTB_FLAG) { 18360c3da918SRichard Henderson qemu_fprintf(f, " DRTB"); 18370c3da918SRichard Henderson } 18380c3da918SRichard Henderson if (iflags & ESR_ESS_FLAG) { 18390c3da918SRichard Henderson qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK); 18402ead1b18SJoe Komlodi } 1841fcf5ef2aSThomas Huth 18420c3da918SRichard Henderson qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" 184319f27b6cSRichard Henderson "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n", 18440c3da918SRichard Henderson env->esr, env->fsr, env->btr, env->edr, 18450c3da918SRichard Henderson env->ear, env->slr, env->shr); 18460c3da918SRichard Henderson 18470c3da918SRichard Henderson for (i = 0; i < 32; i++) { 18480c3da918SRichard Henderson qemu_fprintf(f, "r%2.2d=%08x%c", 18490c3da918SRichard Henderson i, env->regs[i], i % 4 == 3 ? '\n' : ' '); 18500c3da918SRichard Henderson } 18510c3da918SRichard Henderson qemu_fprintf(f, "\n"); 1852fcf5ef2aSThomas Huth } 1853fcf5ef2aSThomas Huth 1854fcf5ef2aSThomas Huth void mb_tcg_init(void) 1855fcf5ef2aSThomas Huth { 1856480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1857480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1858fcf5ef2aSThomas Huth 1859480d29a8SRichard Henderson static const struct { 1860480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1861480d29a8SRichard Henderson } i32s[] = { 1862e47c2231SRichard Henderson /* 1863e47c2231SRichard Henderson * Note that r0 is handled specially in reg_for_read 1864e47c2231SRichard Henderson * and reg_for_write. Nothing should touch cpu_R[0]. 1865e47c2231SRichard Henderson * Leave that element NULL, which will assert quickly 1866e47c2231SRichard Henderson * inside the tcg generator functions. 1867e47c2231SRichard Henderson */ 1868e47c2231SRichard Henderson R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1869480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1870480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1871480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1872480d29a8SRichard Henderson 1873480d29a8SRichard Henderson SP(pc), 1874480d29a8SRichard Henderson SP(msr), 18751074c0fbSRichard Henderson SP(msr_c), 1876480d29a8SRichard Henderson SP(imm), 1877480d29a8SRichard Henderson SP(iflags), 1878b9c58aabSRichard Henderson SP(bvalue), 1879480d29a8SRichard Henderson SP(btarget), 1880480d29a8SRichard Henderson SP(res_val), 1881480d29a8SRichard Henderson }; 1882480d29a8SRichard Henderson 1883480d29a8SRichard Henderson #undef R 1884480d29a8SRichard Henderson #undef SP 1885480d29a8SRichard Henderson 1886480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1887480d29a8SRichard Henderson *i32s[i].var = 1888480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1889fcf5ef2aSThomas Huth } 189076e8187dSRichard Henderson 1891480d29a8SRichard Henderson cpu_res_addr = 1892480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1893fcf5ef2aSThomas Huth } 1894