1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * Xilinx MicroBlaze emulation for qemu: main translation routines. 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2009 Edgar E. Iglesias. 5fcf5ef2aSThomas Huth * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 6fcf5ef2aSThomas Huth * 7fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or 8fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public 9fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either 10ee452036SChetan Pant * version 2.1 of the License, or (at your option) any later version. 11fcf5ef2aSThomas Huth * 12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fcf5ef2aSThomas Huth * Lesser General Public License for more details. 16fcf5ef2aSThomas Huth * 17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fcf5ef2aSThomas Huth */ 20fcf5ef2aSThomas Huth 21fcf5ef2aSThomas Huth #include "qemu/osdep.h" 22fcf5ef2aSThomas Huth #include "cpu.h" 23fcf5ef2aSThomas Huth #include "disas/disas.h" 24fcf5ef2aSThomas Huth #include "exec/exec-all.h" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 26fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 27fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h" 28fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 2977fc6f5eSLluís Vilanova #include "exec/translator.h" 3090c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 31fcf5ef2aSThomas Huth 32fcf5ef2aSThomas Huth #include "exec/log.h" 33fcf5ef2aSThomas Huth 34fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 35fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 36fcf5ef2aSThomas Huth 3777fc6f5eSLluís Vilanova /* is_jmp field values */ 3877fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 3917e77796SRichard Henderson #define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */ 4077fc6f5eSLluís Vilanova 41f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */ 42f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2 43f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */ 44f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3 45f6278ca9SRichard Henderson 46cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 470f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 483e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 491074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 509b158558SRichard Henderson static TCGv_i32 cpu_imm; 51b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue; 520f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 539b158558SRichard Henderson static TCGv_i32 cpu_iflags; 549b158558SRichard Henderson static TCGv cpu_res_addr; 559b158558SRichard Henderson static TCGv_i32 cpu_res_val; 56fcf5ef2aSThomas Huth 57fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 58fcf5ef2aSThomas Huth 59fcf5ef2aSThomas Huth /* This is the state at translation time. */ 60fcf5ef2aSThomas Huth typedef struct DisasContext { 61d4705ae0SRichard Henderson DisasContextBase base; 624b893631SRichard Henderson const MicroBlazeCPUConfig *cfg; 63fcf5ef2aSThomas Huth 64683a247eSRichard Henderson /* TCG op of the current insn_start. */ 65683a247eSRichard Henderson TCGOp *insn_start; 66683a247eSRichard Henderson 6720800179SRichard Henderson TCGv_i32 r0; 6820800179SRichard Henderson bool r0_set; 6920800179SRichard Henderson 70fcf5ef2aSThomas Huth /* Decoder. */ 71d7ecb757SRichard Henderson uint32_t ext_imm; 72683a247eSRichard Henderson unsigned int tb_flags; 736f9642d7SRichard Henderson unsigned int tb_flags_to_set; 74287b1defSRichard Henderson int mem_index; 75fcf5ef2aSThomas Huth 76b9c58aabSRichard Henderson /* Condition under which to jump, including NEVER and ALWAYS. */ 77b9c58aabSRichard Henderson TCGCond jmp_cond; 78b9c58aabSRichard Henderson 79b9c58aabSRichard Henderson /* Immediate branch-taken destination, or -1 for indirect. */ 80b9c58aabSRichard Henderson uint32_t jmp_dest; 81fcf5ef2aSThomas Huth } DisasContext; 82fcf5ef2aSThomas Huth 8320800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8420800179SRichard Henderson { 8520800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 8620800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 8720800179SRichard Henderson } 8820800179SRichard Henderson return x; 8920800179SRichard Henderson } 9020800179SRichard Henderson 9144d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9244d1432bSRichard Henderson #include "decode-insns.c.inc" 9344d1432bSRichard Henderson 94683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc) 95fcf5ef2aSThomas Huth { 96fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 9788e74b61SRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) { 9888e74b61SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK); 99fcf5ef2aSThomas Huth } 100fcf5ef2aSThomas Huth } 101fcf5ef2aSThomas Huth 10241ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 103fcf5ef2aSThomas Huth { 104*a5ea3dd7SRichard Henderson gen_helper_raise_exception(cpu_env, tcg_constant_i32(index)); 105d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 106fcf5ef2aSThomas Huth } 107fcf5ef2aSThomas Huth 10841ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 10941ba37c4SRichard Henderson { 11041ba37c4SRichard Henderson t_sync_flags(dc); 111d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 11241ba37c4SRichard Henderson gen_raise_exception(dc, index); 11341ba37c4SRichard Henderson } 11441ba37c4SRichard Henderson 11541ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 11641ba37c4SRichard Henderson { 117*a5ea3dd7SRichard Henderson TCGv_i32 tmp = tcg_constant_i32(esr_ec); 11841ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 11941ba37c4SRichard Henderson 12041ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 12141ba37c4SRichard Henderson } 12241ba37c4SRichard Henderson 123fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 124fcf5ef2aSThomas Huth { 12566345580SRichard Henderson if (translator_use_goto_tb(&dc->base, dest)) { 126fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1270f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 128d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 129fcf5ef2aSThomas Huth } else { 1300f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1314059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr(); 132fcf5ef2aSThomas Huth } 133d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 134fcf5ef2aSThomas Huth } 135fcf5ef2aSThomas Huth 136bdfc1e88SEdgar E. Iglesias /* 1379ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1389ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1399ba8cd45SEdgar E. Iglesias */ 1409ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1419ba8cd45SEdgar E. Iglesias { 1422c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE) 1434b893631SRichard Henderson && dc->cfg->illegal_opcode_exception) { 14441ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1459ba8cd45SEdgar E. Iglesias } 1469ba8cd45SEdgar E. Iglesias return cond; 1479ba8cd45SEdgar E. Iglesias } 1489ba8cd45SEdgar E. Iglesias 1499ba8cd45SEdgar E. Iglesias /* 150bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 151bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 152bdfc1e88SEdgar E. Iglesias */ 153bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 154bdfc1e88SEdgar E. Iglesias { 155287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX; 156bdfc1e88SEdgar E. Iglesias 1572c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) { 15841ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 159bdfc1e88SEdgar E. Iglesias } 160bdfc1e88SEdgar E. Iglesias return cond_user; 161bdfc1e88SEdgar E. Iglesias } 162bdfc1e88SEdgar E. Iglesias 1632a7567a2SRichard Henderson /* 1642a7567a2SRichard Henderson * Return true, and log an error, if the current insn is 1652a7567a2SRichard Henderson * within a delay slot. 1662a7567a2SRichard Henderson */ 1672a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type) 1682a7567a2SRichard Henderson { 1692a7567a2SRichard Henderson if (dc->tb_flags & D_FLAG) { 1702a7567a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 1712a7567a2SRichard Henderson "Invalid insn in delay slot: %s at %08x\n", 1722a7567a2SRichard Henderson insn_type, (uint32_t)dc->base.pc_next); 1732a7567a2SRichard Henderson return true; 1742a7567a2SRichard Henderson } 1752a7567a2SRichard Henderson return false; 1762a7567a2SRichard Henderson } 1772a7567a2SRichard Henderson 17820800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 179fcf5ef2aSThomas Huth { 18020800179SRichard Henderson if (likely(reg != 0)) { 18120800179SRichard Henderson return cpu_R[reg]; 182fcf5ef2aSThomas Huth } 18320800179SRichard Henderson if (!dc->r0_set) { 18420800179SRichard Henderson if (dc->r0 == NULL) { 18520800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 186fcf5ef2aSThomas Huth } 18720800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 18820800179SRichard Henderson dc->r0_set = true; 18920800179SRichard Henderson } 19020800179SRichard Henderson return dc->r0; 191fcf5ef2aSThomas Huth } 192fcf5ef2aSThomas Huth 19320800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 19420800179SRichard Henderson { 19520800179SRichard Henderson if (likely(reg != 0)) { 19620800179SRichard Henderson return cpu_R[reg]; 19720800179SRichard Henderson } 19820800179SRichard Henderson if (dc->r0 == NULL) { 19920800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 20020800179SRichard Henderson } 20120800179SRichard Henderson return dc->r0; 202fcf5ef2aSThomas Huth } 203fcf5ef2aSThomas Huth 20420800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 20520800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 20620800179SRichard Henderson { 20720800179SRichard Henderson TCGv_i32 rd, ra, rb; 20820800179SRichard Henderson 20920800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 21020800179SRichard Henderson return true; 211fcf5ef2aSThomas Huth } 21220800179SRichard Henderson 21320800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 21420800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 21520800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 21620800179SRichard Henderson fn(rd, ra, rb); 21720800179SRichard Henderson return true; 21820800179SRichard Henderson } 21920800179SRichard Henderson 22039cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, 22139cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32)) 22239cf3864SRichard Henderson { 22339cf3864SRichard Henderson TCGv_i32 rd, ra; 22439cf3864SRichard Henderson 22539cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) { 22639cf3864SRichard Henderson return true; 22739cf3864SRichard Henderson } 22839cf3864SRichard Henderson 22939cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd); 23039cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra); 23139cf3864SRichard Henderson fn(rd, ra); 23239cf3864SRichard Henderson return true; 23339cf3864SRichard Henderson } 23439cf3864SRichard Henderson 23520800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 23620800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 23720800179SRichard Henderson { 23820800179SRichard Henderson TCGv_i32 rd, ra; 23920800179SRichard Henderson 24020800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 24120800179SRichard Henderson return true; 24220800179SRichard Henderson } 24320800179SRichard Henderson 24420800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 24520800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 24620800179SRichard Henderson fni(rd, ra, arg->imm); 24720800179SRichard Henderson return true; 24820800179SRichard Henderson } 24920800179SRichard Henderson 25020800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 25120800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 25220800179SRichard Henderson { 25320800179SRichard Henderson TCGv_i32 rd, ra, imm; 25420800179SRichard Henderson 25520800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 25620800179SRichard Henderson return true; 25720800179SRichard Henderson } 25820800179SRichard Henderson 25920800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 26020800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 261*a5ea3dd7SRichard Henderson imm = tcg_constant_i32(arg->imm); 26220800179SRichard Henderson 26320800179SRichard Henderson fn(rd, ra, imm); 26420800179SRichard Henderson return true; 26520800179SRichard Henderson } 26620800179SRichard Henderson 26720800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 26820800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 26920800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 27020800179SRichard Henderson 271607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 272607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 2734b893631SRichard Henderson { return dc->cfg->CFG && do_typea(dc, a, SE, FN); } 274607f5767SRichard Henderson 27539cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 27639cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 27739cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 27839cf3864SRichard Henderson 27939cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 28039cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 2814b893631SRichard Henderson { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); } 28239cf3864SRichard Henderson 28320800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 28420800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 28520800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 28620800179SRichard Henderson 28797955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 28897955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 2894b893631SRichard Henderson { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); } 29097955cebSRichard Henderson 29120800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 29220800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29320800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 29420800179SRichard Henderson 295d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 296d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 297d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 298d5aead3dSRichard Henderson 299d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 300d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 301d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 302d5aead3dSRichard Henderson 30320800179SRichard Henderson /* No input carry, but output carry. */ 30420800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 30520800179SRichard Henderson { 306*a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0); 30720800179SRichard Henderson 30820800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 30920800179SRichard Henderson } 31020800179SRichard Henderson 31120800179SRichard Henderson /* Input and output carry. */ 31220800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 31320800179SRichard Henderson { 314*a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0); 31520800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 31620800179SRichard Henderson 31720800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 31820800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 31920800179SRichard Henderson } 32020800179SRichard Henderson 32120800179SRichard Henderson /* Input carry, but no output carry. */ 32220800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 32320800179SRichard Henderson { 32420800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 32520800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 32620800179SRichard Henderson } 32720800179SRichard Henderson 32820800179SRichard Henderson DO_TYPEA(add, true, gen_add) 32920800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 33020800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 33120800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 33220800179SRichard Henderson 33320800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 33420800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 33520800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 33620800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 33720800179SRichard Henderson 338cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 339cb0a0a4cSRichard Henderson { 340cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 341cb0a0a4cSRichard Henderson } 342cb0a0a4cSRichard Henderson 343cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 344cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 345cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 346cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 347cb0a0a4cSRichard Henderson 348081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 349081d8e02SRichard Henderson { 350081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 351081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 352081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 353081d8e02SRichard Henderson } 354081d8e02SRichard Henderson 355081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 356081d8e02SRichard Henderson { 357081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 358081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 359081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 360081d8e02SRichard Henderson } 361081d8e02SRichard Henderson 362081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 363081d8e02SRichard Henderson { 364081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 365081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 366081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 367081d8e02SRichard Henderson } 368081d8e02SRichard Henderson 369081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 370081d8e02SRichard Henderson { 371081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 372081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 373081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 374081d8e02SRichard Henderson 375081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 376081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 377081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 378081d8e02SRichard Henderson imm_w, imm_s); 379081d8e02SRichard Henderson } else { 380081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 381081d8e02SRichard Henderson } 382081d8e02SRichard Henderson } 383081d8e02SRichard Henderson 384081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 385081d8e02SRichard Henderson { 386081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 387081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 388081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 389081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 390081d8e02SRichard Henderson 391081d8e02SRichard Henderson if (imm_w < imm_s) { 392081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 393081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 394081d8e02SRichard Henderson imm_w, imm_s); 395081d8e02SRichard Henderson } else { 396081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 397081d8e02SRichard Henderson } 398081d8e02SRichard Henderson } 399081d8e02SRichard Henderson 400081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 401081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 402081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 403081d8e02SRichard Henderson 404081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 405081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 406081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 407081d8e02SRichard Henderson 408081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 409081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 410081d8e02SRichard Henderson 41139cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 41239cf3864SRichard Henderson { 41339cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 41439cf3864SRichard Henderson } 41539cf3864SRichard Henderson 41639cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 41739cf3864SRichard Henderson 41858b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 41958b48b63SRichard Henderson { 42058b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 42158b48b63SRichard Henderson 42258b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 42358b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 42458b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 42558b48b63SRichard Henderson } 42658b48b63SRichard Henderson 42758b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 42858b48b63SRichard Henderson { 42958b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 43058b48b63SRichard Henderson 43158b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 43258b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 43358b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 43458b48b63SRichard Henderson } 43558b48b63SRichard Henderson 43658b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 43758b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 438a2b0b90eSRichard Henderson 439d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 440d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 441d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 442d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 443d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 444d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 445d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 446d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 447d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 448d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 449d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 450d5aead3dSRichard Henderson 451d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 452d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 453d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 454d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 455d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 456d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 457d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 458d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 459d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 460d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 461d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 462d5aead3dSRichard Henderson 463d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 464d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 465d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 466d5aead3dSRichard Henderson 467d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 468d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 469d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 470d5aead3dSRichard Henderson 471d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 472b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 473b1354342SRichard Henderson { 474b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 475b1354342SRichard Henderson } 476b1354342SRichard Henderson 477b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 478b1354342SRichard Henderson { 479b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 480b1354342SRichard Henderson } 481b1354342SRichard Henderson 482b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 483b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 484b1354342SRichard Henderson 485e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 486e64b2e5cSRichard Henderson { 4872a7567a2SRichard Henderson if (invalid_delay_slot(dc, "imm")) { 4882a7567a2SRichard Henderson return true; 4892a7567a2SRichard Henderson } 490e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 491e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 4926f9642d7SRichard Henderson dc->tb_flags_to_set = IMM_FLAG; 493e64b2e5cSRichard Henderson return true; 494e64b2e5cSRichard Henderson } 495e64b2e5cSRichard Henderson 49697955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 49797955cebSRichard Henderson { 49897955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 49997955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 50097955cebSRichard Henderson } 50197955cebSRichard Henderson 50297955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 50397955cebSRichard Henderson { 50497955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 50597955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 50697955cebSRichard Henderson } 50797955cebSRichard Henderson 50897955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 50997955cebSRichard Henderson { 51097955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 51197955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 51297955cebSRichard Henderson } 51397955cebSRichard Henderson 51497955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 51597955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 51697955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 51797955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 51897955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 51997955cebSRichard Henderson 520cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 521cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 522cb0a0a4cSRichard Henderson 523607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 524607f5767SRichard Henderson { 525607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 526607f5767SRichard Henderson } 527607f5767SRichard Henderson 528607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 529607f5767SRichard Henderson { 530607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 531607f5767SRichard Henderson } 532607f5767SRichard Henderson 533607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 534607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 535607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 536607f5767SRichard Henderson 537a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 538a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 539a2b0b90eSRichard Henderson { 540a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 541a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 542a2b0b90eSRichard Henderson } 543a2b0b90eSRichard Henderson 544a2b0b90eSRichard Henderson /* Input and output carry. */ 545a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 546a2b0b90eSRichard Henderson { 547*a5ea3dd7SRichard Henderson TCGv_i32 zero = tcg_constant_i32(0); 548a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 549a2b0b90eSRichard Henderson 550a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 551a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 552a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 553a2b0b90eSRichard Henderson } 554a2b0b90eSRichard Henderson 555a2b0b90eSRichard Henderson /* No input or output carry. */ 556a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 557a2b0b90eSRichard Henderson { 558a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 559a2b0b90eSRichard Henderson } 560a2b0b90eSRichard Henderson 561a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 562a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 563a2b0b90eSRichard Henderson { 564a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 565a2b0b90eSRichard Henderson 566a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 567a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 568a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 569a2b0b90eSRichard Henderson } 570a2b0b90eSRichard Henderson 571a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 572a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 573a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 574a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 575a2b0b90eSRichard Henderson 576a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 577a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 578a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 579a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 580a2b0b90eSRichard Henderson 58139cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 58239cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 58339cf3864SRichard Henderson 58439cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 58539cf3864SRichard Henderson { 58639cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 58739cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 58839cf3864SRichard Henderson } 58939cf3864SRichard Henderson 59039cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 59139cf3864SRichard Henderson { 59239cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 59339cf3864SRichard Henderson 59439cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 59539cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 59639cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 59739cf3864SRichard Henderson } 59839cf3864SRichard Henderson 59939cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 60039cf3864SRichard Henderson { 60139cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 60239cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 60339cf3864SRichard Henderson } 60439cf3864SRichard Henderson 60539cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 60639cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 60739cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 60839cf3864SRichard Henderson 60939cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 61039cf3864SRichard Henderson { 61139cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 61239cf3864SRichard Henderson } 61339cf3864SRichard Henderson 61439cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 61539cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 61639cf3864SRichard Henderson 61739cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 61839cf3864SRichard Henderson { 61939cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 62039cf3864SRichard Henderson trap_userspace(dc, true); 62139cf3864SRichard Henderson return true; 62239cf3864SRichard Henderson } 62339cf3864SRichard Henderson 624cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 625cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 626cb0a0a4cSRichard Henderson 627d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 628d8e59c4aSRichard Henderson { 629d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 630d8e59c4aSRichard Henderson 631d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 632d8e59c4aSRichard Henderson if (ra && rb) { 633d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 634d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 635d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 636d8e59c4aSRichard Henderson } else if (ra) { 637d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 638d8e59c4aSRichard Henderson } else if (rb) { 639d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 640d8e59c4aSRichard Henderson } else { 641d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 642d8e59c4aSRichard Henderson } 643d8e59c4aSRichard Henderson 6444b893631SRichard Henderson if ((ra == 1 || rb == 1) && dc->cfg->stackprot) { 645d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 646d8e59c4aSRichard Henderson } 647d8e59c4aSRichard Henderson return ret; 648d8e59c4aSRichard Henderson } 649d8e59c4aSRichard Henderson 650d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 651d8e59c4aSRichard Henderson { 652d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 653d8e59c4aSRichard Henderson 654d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 655d8e59c4aSRichard Henderson if (ra) { 656d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 657d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 658d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 659d8e59c4aSRichard Henderson } else { 660d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 661d8e59c4aSRichard Henderson } 662d8e59c4aSRichard Henderson 6634b893631SRichard Henderson if (ra == 1 && dc->cfg->stackprot) { 664d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 665d8e59c4aSRichard Henderson } 666d8e59c4aSRichard Henderson return ret; 667d8e59c4aSRichard Henderson } 668d8e59c4aSRichard Henderson 66919f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY 670d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 671d8e59c4aSRichard Henderson { 6724b893631SRichard Henderson int addr_size = dc->cfg->addr_size; 673d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 674d8e59c4aSRichard Henderson 675d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 676d8e59c4aSRichard Henderson if (rb) { 677d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 678d8e59c4aSRichard Henderson } else { 679d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 680d8e59c4aSRichard Henderson } 681d8e59c4aSRichard Henderson } else { 682d8e59c4aSRichard Henderson if (rb) { 683d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 684d8e59c4aSRichard Henderson } else { 685d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 686d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 687d8e59c4aSRichard Henderson } 688d8e59c4aSRichard Henderson if (addr_size < 64) { 689d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 690d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 691d8e59c4aSRichard Henderson } 692d8e59c4aSRichard Henderson } 693d8e59c4aSRichard Henderson return ret; 694d8e59c4aSRichard Henderson } 69519f27b6cSRichard Henderson #endif 696d8e59c4aSRichard Henderson 697b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY 698ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd, 699ab0c8d0fSRichard Henderson MemOp size, bool store) 700ab0c8d0fSRichard Henderson { 701ab0c8d0fSRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); 702ab0c8d0fSRichard Henderson 703ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG; 704ab0c8d0fSRichard Henderson iflags |= rd << 5; 705ab0c8d0fSRichard Henderson iflags |= store * ESR_S; 706ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W; 707ab0c8d0fSRichard Henderson 708ab0c8d0fSRichard Henderson tcg_set_insn_start_param(dc->insn_start, 1, iflags); 709ab0c8d0fSRichard Henderson } 710b414df75SRichard Henderson #endif 711ab0c8d0fSRichard Henderson 712d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 713d8e59c4aSRichard Henderson int mem_index, bool rev) 714d8e59c4aSRichard Henderson { 715d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 716d8e59c4aSRichard Henderson 717d8e59c4aSRichard Henderson /* 718d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 719d8e59c4aSRichard Henderson * 720d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 721d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 722d8e59c4aSRichard Henderson */ 723d8e59c4aSRichard Henderson if (rev) { 724d8e59c4aSRichard Henderson if (size > MO_8) { 725d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 726d8e59c4aSRichard Henderson } 727d8e59c4aSRichard Henderson if (size < MO_32) { 728d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 729d8e59c4aSRichard Henderson } 730d8e59c4aSRichard Henderson } 731d8e59c4aSRichard Henderson 732b414df75SRichard Henderson /* 733b414df75SRichard Henderson * For system mode, enforce alignment if the cpu configuration 734b414df75SRichard Henderson * requires it. For user-mode, the Linux kernel will have fixed up 735b414df75SRichard Henderson * any unaligned access, so emulate that by *not* setting MO_ALIGN. 736b414df75SRichard Henderson */ 737b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY 738ab0c8d0fSRichard Henderson if (size > MO_8 && 739ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 7404b893631SRichard Henderson dc->cfg->unaligned_exceptions) { 741ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false); 742ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 743d8e59c4aSRichard Henderson } 744b414df75SRichard Henderson #endif 745d8e59c4aSRichard Henderson 746ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); 747d8e59c4aSRichard Henderson return true; 748d8e59c4aSRichard Henderson } 749d8e59c4aSRichard Henderson 750d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 751d8e59c4aSRichard Henderson { 752d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 753d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 754d8e59c4aSRichard Henderson } 755d8e59c4aSRichard Henderson 756d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 757d8e59c4aSRichard Henderson { 758d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 759d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 760d8e59c4aSRichard Henderson } 761d8e59c4aSRichard Henderson 762d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 763d8e59c4aSRichard Henderson { 764d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 765d8e59c4aSRichard Henderson return true; 766d8e59c4aSRichard Henderson } 76719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 76819f27b6cSRichard Henderson return true; 76919f27b6cSRichard Henderson #else 770d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 771d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 77219f27b6cSRichard Henderson #endif 773d8e59c4aSRichard Henderson } 774d8e59c4aSRichard Henderson 775d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 776d8e59c4aSRichard Henderson { 777d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 778d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 779d8e59c4aSRichard Henderson } 780d8e59c4aSRichard Henderson 781d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 782d8e59c4aSRichard Henderson { 783d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 784d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 785d8e59c4aSRichard Henderson } 786d8e59c4aSRichard Henderson 787d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 788d8e59c4aSRichard Henderson { 789d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 790d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 791d8e59c4aSRichard Henderson } 792d8e59c4aSRichard Henderson 793d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 794d8e59c4aSRichard Henderson { 795d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 796d8e59c4aSRichard Henderson return true; 797d8e59c4aSRichard Henderson } 79819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 79919f27b6cSRichard Henderson return true; 80019f27b6cSRichard Henderson #else 801d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 802d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 80319f27b6cSRichard Henderson #endif 804d8e59c4aSRichard Henderson } 805d8e59c4aSRichard Henderson 806d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 807d8e59c4aSRichard Henderson { 808d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 809d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 810d8e59c4aSRichard Henderson } 811d8e59c4aSRichard Henderson 812d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 813d8e59c4aSRichard Henderson { 814d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 815d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 816d8e59c4aSRichard Henderson } 817d8e59c4aSRichard Henderson 818d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 819d8e59c4aSRichard Henderson { 820d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 821d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 822d8e59c4aSRichard Henderson } 823d8e59c4aSRichard Henderson 824d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 825d8e59c4aSRichard Henderson { 826d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 827d8e59c4aSRichard Henderson return true; 828d8e59c4aSRichard Henderson } 82919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 83019f27b6cSRichard Henderson return true; 83119f27b6cSRichard Henderson #else 832d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 833d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 83419f27b6cSRichard Henderson #endif 835d8e59c4aSRichard Henderson } 836d8e59c4aSRichard Henderson 837d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg) 838d8e59c4aSRichard Henderson { 839d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 840d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 841d8e59c4aSRichard Henderson } 842d8e59c4aSRichard Henderson 843d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg) 844d8e59c4aSRichard Henderson { 845d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 846d8e59c4aSRichard Henderson 847d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */ 848d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 849d8e59c4aSRichard Henderson 850d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); 851d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 852d8e59c4aSRichard Henderson 853d8e59c4aSRichard Henderson if (arg->rd) { 854d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 855d8e59c4aSRichard Henderson } 856d8e59c4aSRichard Henderson 857d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 858d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 859d8e59c4aSRichard Henderson return true; 860d8e59c4aSRichard Henderson } 861d8e59c4aSRichard Henderson 862d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 863d8e59c4aSRichard Henderson int mem_index, bool rev) 864d8e59c4aSRichard Henderson { 865d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 866d8e59c4aSRichard Henderson 867d8e59c4aSRichard Henderson /* 868d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 869d8e59c4aSRichard Henderson * 870d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 871d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 872d8e59c4aSRichard Henderson */ 873d8e59c4aSRichard Henderson if (rev) { 874d8e59c4aSRichard Henderson if (size > MO_8) { 875d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 876d8e59c4aSRichard Henderson } 877d8e59c4aSRichard Henderson if (size < MO_32) { 878d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 879d8e59c4aSRichard Henderson } 880d8e59c4aSRichard Henderson } 881d8e59c4aSRichard Henderson 882b414df75SRichard Henderson /* 883b414df75SRichard Henderson * For system mode, enforce alignment if the cpu configuration 884b414df75SRichard Henderson * requires it. For user-mode, the Linux kernel will have fixed up 885b414df75SRichard Henderson * any unaligned access, so emulate that by *not* setting MO_ALIGN. 886b414df75SRichard Henderson */ 887b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY 888ab0c8d0fSRichard Henderson if (size > MO_8 && 889ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 8904b893631SRichard Henderson dc->cfg->unaligned_exceptions) { 891ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true); 892ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 893d8e59c4aSRichard Henderson } 894b414df75SRichard Henderson #endif 895d8e59c4aSRichard Henderson 896ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 897d8e59c4aSRichard Henderson return true; 898d8e59c4aSRichard Henderson } 899d8e59c4aSRichard Henderson 900d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 901d8e59c4aSRichard Henderson { 902d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 903d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 904d8e59c4aSRichard Henderson } 905d8e59c4aSRichard Henderson 906d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 907d8e59c4aSRichard Henderson { 908d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 909d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 910d8e59c4aSRichard Henderson } 911d8e59c4aSRichard Henderson 912d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 913d8e59c4aSRichard Henderson { 914d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 915d8e59c4aSRichard Henderson return true; 916d8e59c4aSRichard Henderson } 91719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 91819f27b6cSRichard Henderson return true; 91919f27b6cSRichard Henderson #else 920d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 921d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 92219f27b6cSRichard Henderson #endif 923d8e59c4aSRichard Henderson } 924d8e59c4aSRichard Henderson 925d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 926d8e59c4aSRichard Henderson { 927d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 928d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 929d8e59c4aSRichard Henderson } 930d8e59c4aSRichard Henderson 931d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg) 932d8e59c4aSRichard Henderson { 933d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 934d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 935d8e59c4aSRichard Henderson } 936d8e59c4aSRichard Henderson 937d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 938d8e59c4aSRichard Henderson { 939d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 940d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 941d8e59c4aSRichard Henderson } 942d8e59c4aSRichard Henderson 943d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 944d8e59c4aSRichard Henderson { 945d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 946d8e59c4aSRichard Henderson return true; 947d8e59c4aSRichard Henderson } 94819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 94919f27b6cSRichard Henderson return true; 95019f27b6cSRichard Henderson #else 951d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 952d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 95319f27b6cSRichard Henderson #endif 954d8e59c4aSRichard Henderson } 955d8e59c4aSRichard Henderson 956d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 957d8e59c4aSRichard Henderson { 958d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 959d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 960d8e59c4aSRichard Henderson } 961d8e59c4aSRichard Henderson 962d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 963d8e59c4aSRichard Henderson { 964d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 965d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 966d8e59c4aSRichard Henderson } 967d8e59c4aSRichard Henderson 968d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 969d8e59c4aSRichard Henderson { 970d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 971d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 972d8e59c4aSRichard Henderson } 973d8e59c4aSRichard Henderson 974d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 975d8e59c4aSRichard Henderson { 976d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 977d8e59c4aSRichard Henderson return true; 978d8e59c4aSRichard Henderson } 97919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY 98019f27b6cSRichard Henderson return true; 98119f27b6cSRichard Henderson #else 982d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 983d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 98419f27b6cSRichard Henderson #endif 985d8e59c4aSRichard Henderson } 986d8e59c4aSRichard Henderson 987d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 988d8e59c4aSRichard Henderson { 989d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 990d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 991d8e59c4aSRichard Henderson } 992d8e59c4aSRichard Henderson 993d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 994d8e59c4aSRichard Henderson { 995d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 996d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 997d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 998d8e59c4aSRichard Henderson TCGv_i32 tval; 999d8e59c4aSRichard Henderson 1000d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 1001d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1002d8e59c4aSRichard Henderson 1003d8e59c4aSRichard Henderson /* 1004d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 1005d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 1006d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 1007d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 1008d8e59c4aSRichard Henderson */ 1009d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 1010d8e59c4aSRichard Henderson 1011d8e59c4aSRichard Henderson /* 1012d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 1013d8e59c4aSRichard Henderson * the reserved location. 1014d8e59c4aSRichard Henderson */ 1015d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1016d8e59c4aSRichard Henderson 1017d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1018d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1019d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1020d8e59c4aSRichard Henderson 1021d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1022d8e59c4aSRichard Henderson 1023d8e59c4aSRichard Henderson /* Success */ 1024d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1025d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1026d8e59c4aSRichard Henderson 1027d8e59c4aSRichard Henderson /* Failure */ 1028d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1029d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1030d8e59c4aSRichard Henderson 1031d8e59c4aSRichard Henderson gen_set_label(swx_done); 1032d8e59c4aSRichard Henderson 1033d8e59c4aSRichard Henderson /* 1034d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1035d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1036d8e59c4aSRichard Henderson */ 1037d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1038d8e59c4aSRichard Henderson return true; 1039d8e59c4aSRichard Henderson } 1040d8e59c4aSRichard Henderson 104116bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b) 104216bbbbc9SRichard Henderson { 104316bbbbc9SRichard Henderson dc->tb_flags_to_set |= D_FLAG; 104416bbbbc9SRichard Henderson if (type_b && (dc->tb_flags & IMM_FLAG)) { 104516bbbbc9SRichard Henderson dc->tb_flags_to_set |= BIMM_FLAG; 104616bbbbc9SRichard Henderson } 104716bbbbc9SRichard Henderson } 104816bbbbc9SRichard Henderson 104916bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm, 105016bbbbc9SRichard Henderson bool delay, bool abs, int link) 105116bbbbc9SRichard Henderson { 105216bbbbc9SRichard Henderson uint32_t add_pc; 105316bbbbc9SRichard Henderson 10542a7567a2SRichard Henderson if (invalid_delay_slot(dc, "branch")) { 10552a7567a2SRichard Henderson return true; 10562a7567a2SRichard Henderson } 105716bbbbc9SRichard Henderson if (delay) { 105816bbbbc9SRichard Henderson setup_dslot(dc, dest_rb < 0); 105916bbbbc9SRichard Henderson } 106016bbbbc9SRichard Henderson 106116bbbbc9SRichard Henderson if (link) { 106216bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next); 106316bbbbc9SRichard Henderson } 106416bbbbc9SRichard Henderson 106516bbbbc9SRichard Henderson /* Store the branch taken destination into btarget. */ 106616bbbbc9SRichard Henderson add_pc = abs ? 0 : dc->base.pc_next; 106716bbbbc9SRichard Henderson if (dest_rb > 0) { 106816bbbbc9SRichard Henderson dc->jmp_dest = -1; 106916bbbbc9SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc); 107016bbbbc9SRichard Henderson } else { 107116bbbbc9SRichard Henderson dc->jmp_dest = add_pc + dest_imm; 107216bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 107316bbbbc9SRichard Henderson } 107416bbbbc9SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 107516bbbbc9SRichard Henderson return true; 107616bbbbc9SRichard Henderson } 107716bbbbc9SRichard Henderson 107816bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \ 107916bbbbc9SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \ 108016bbbbc9SRichard Henderson { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \ 108116bbbbc9SRichard Henderson static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \ 108216bbbbc9SRichard Henderson { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); } 108316bbbbc9SRichard Henderson 108416bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false) 108516bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false) 108616bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false) 108716bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false) 108816bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true) 108916bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true) 109016bbbbc9SRichard Henderson 1091fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm, 1092fd779113SRichard Henderson TCGCond cond, int ra, bool delay) 1093fd779113SRichard Henderson { 1094fd779113SRichard Henderson TCGv_i32 zero, next; 1095fd779113SRichard Henderson 10962a7567a2SRichard Henderson if (invalid_delay_slot(dc, "bcc")) { 10972a7567a2SRichard Henderson return true; 10982a7567a2SRichard Henderson } 1099fd779113SRichard Henderson if (delay) { 1100fd779113SRichard Henderson setup_dslot(dc, dest_rb < 0); 1101fd779113SRichard Henderson } 1102fd779113SRichard Henderson 1103fd779113SRichard Henderson dc->jmp_cond = cond; 1104fd779113SRichard Henderson 1105fd779113SRichard Henderson /* Cache the condition register in cpu_bvalue across any delay slot. */ 1106fd779113SRichard Henderson tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra)); 1107fd779113SRichard Henderson 1108fd779113SRichard Henderson /* Store the branch taken destination into btarget. */ 1109fd779113SRichard Henderson if (dest_rb > 0) { 1110fd779113SRichard Henderson dc->jmp_dest = -1; 1111fd779113SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next); 1112fd779113SRichard Henderson } else { 1113fd779113SRichard Henderson dc->jmp_dest = dc->base.pc_next + dest_imm; 1114fd779113SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 1115fd779113SRichard Henderson } 1116fd779113SRichard Henderson 1117fd779113SRichard Henderson /* Compute the final destination into btarget. */ 1118*a5ea3dd7SRichard Henderson zero = tcg_constant_i32(0); 1119*a5ea3dd7SRichard Henderson next = tcg_constant_i32(dc->base.pc_next + (delay + 1) * 4); 1120fd779113SRichard Henderson tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, 1121fd779113SRichard Henderson reg_for_read(dc, ra), zero, 1122fd779113SRichard Henderson cpu_btarget, next); 1123fd779113SRichard Henderson 1124fd779113SRichard Henderson return true; 1125fd779113SRichard Henderson } 1126fd779113SRichard Henderson 1127fd779113SRichard Henderson #define DO_BCC(NAME, COND) \ 1128fd779113SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \ 1129fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \ 1130fd779113SRichard Henderson static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \ 1131fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \ 1132fd779113SRichard Henderson static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \ 1133fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \ 1134fd779113SRichard Henderson static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \ 1135fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); } 1136fd779113SRichard Henderson 1137fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ) 1138fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE) 1139fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT) 1140fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE) 1141fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT) 1142fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE) 1143fd779113SRichard Henderson 1144f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg) 1145f5235314SRichard Henderson { 1146f5235314SRichard Henderson if (trap_userspace(dc, true)) { 1147f5235314SRichard Henderson return true; 1148f5235314SRichard Henderson } 11492a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brk")) { 11502a7567a2SRichard Henderson return true; 11512a7567a2SRichard Henderson } 11522a7567a2SRichard Henderson 1153f5235314SRichard Henderson tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb)); 1154f5235314SRichard Henderson if (arg->rd) { 1155f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1156f5235314SRichard Henderson } 1157f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP); 1158f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1159f5235314SRichard Henderson 116017e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1161f5235314SRichard Henderson return true; 1162f5235314SRichard Henderson } 1163f5235314SRichard Henderson 1164f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) 1165f5235314SRichard Henderson { 1166f5235314SRichard Henderson uint32_t imm = arg->imm; 1167f5235314SRichard Henderson 1168f5235314SRichard Henderson if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) { 1169f5235314SRichard Henderson return true; 1170f5235314SRichard Henderson } 11712a7567a2SRichard Henderson if (invalid_delay_slot(dc, "brki")) { 11722a7567a2SRichard Henderson return true; 11732a7567a2SRichard Henderson } 11742a7567a2SRichard Henderson 1175f5235314SRichard Henderson tcg_gen_movi_i32(cpu_pc, imm); 1176f5235314SRichard Henderson if (arg->rd) { 1177f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1178f5235314SRichard Henderson } 1179f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1180f5235314SRichard Henderson 1181f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY 1182f5235314SRichard Henderson switch (imm) { 1183f5235314SRichard Henderson case 0x8: /* syscall trap */ 1184f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_SYSCALL); 1185f5235314SRichard Henderson break; 1186f5235314SRichard Henderson case 0x18: /* debug trap */ 1187f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1188f5235314SRichard Henderson break; 1189f5235314SRichard Henderson default: /* eliminated with trap_userspace check */ 1190f5235314SRichard Henderson g_assert_not_reached(); 1191f5235314SRichard Henderson } 1192f5235314SRichard Henderson #else 1193f5235314SRichard Henderson uint32_t msr_to_set = 0; 1194f5235314SRichard Henderson 1195f5235314SRichard Henderson if (imm != 0x18) { 1196f5235314SRichard Henderson msr_to_set |= MSR_BIP; 1197f5235314SRichard Henderson } 1198f5235314SRichard Henderson if (imm == 0x8 || imm == 0x18) { 1199f5235314SRichard Henderson /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */ 1200f5235314SRichard Henderson msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1; 1201f5235314SRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, 1202f5235314SRichard Henderson ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM)); 1203f5235314SRichard Henderson } 1204f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set); 120517e77796SRichard Henderson dc->base.is_jmp = DISAS_EXIT; 1206f5235314SRichard Henderson #endif 1207f5235314SRichard Henderson 1208f5235314SRichard Henderson return true; 1209f5235314SRichard Henderson } 1210f5235314SRichard Henderson 1211ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg) 1212ee8c7f9fSRichard Henderson { 1213ee8c7f9fSRichard Henderson int mbar_imm = arg->imm; 1214ee8c7f9fSRichard Henderson 12152a7567a2SRichard Henderson /* Note that mbar is a specialized branch instruction. */ 12162a7567a2SRichard Henderson if (invalid_delay_slot(dc, "mbar")) { 12172a7567a2SRichard Henderson return true; 12182a7567a2SRichard Henderson } 12192a7567a2SRichard Henderson 1220ee8c7f9fSRichard Henderson /* Data access memory barrier. */ 1221ee8c7f9fSRichard Henderson if ((mbar_imm & 2) == 0) { 1222ee8c7f9fSRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 1223ee8c7f9fSRichard Henderson } 1224ee8c7f9fSRichard Henderson 1225ee8c7f9fSRichard Henderson /* Sleep. */ 1226ee8c7f9fSRichard Henderson if (mbar_imm & 16) { 1227ee8c7f9fSRichard Henderson if (trap_userspace(dc, true)) { 1228ee8c7f9fSRichard Henderson /* Sleep is a privileged instruction. */ 1229ee8c7f9fSRichard Henderson return true; 1230ee8c7f9fSRichard Henderson } 1231ee8c7f9fSRichard Henderson 1232ee8c7f9fSRichard Henderson t_sync_flags(dc); 1233ee8c7f9fSRichard Henderson 1234*a5ea3dd7SRichard Henderson tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, 1235ee8c7f9fSRichard Henderson -offsetof(MicroBlazeCPU, env) 1236ee8c7f9fSRichard Henderson +offsetof(CPUState, halted)); 1237ee8c7f9fSRichard Henderson 1238ee8c7f9fSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1239ee8c7f9fSRichard Henderson 1240ee8c7f9fSRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1241ee8c7f9fSRichard Henderson } 1242ee8c7f9fSRichard Henderson 1243ee8c7f9fSRichard Henderson /* 1244ee8c7f9fSRichard Henderson * If !(mbar_imm & 1), this is an instruction access memory barrier 1245ee8c7f9fSRichard Henderson * and we need to end the TB so that we recognize self-modified 1246ee8c7f9fSRichard Henderson * code immediately. 1247ee8c7f9fSRichard Henderson * 1248ee8c7f9fSRichard Henderson * However, there are some data mbars that need the TB break 1249ee8c7f9fSRichard Henderson * (and return to main loop) to recognize interrupts right away. 1250ee8c7f9fSRichard Henderson * E.g. recognizing a change to an interrupt controller register. 1251ee8c7f9fSRichard Henderson * 1252ee8c7f9fSRichard Henderson * Therefore, choose to end the TB always. 1253ee8c7f9fSRichard Henderson */ 125443b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1255ee8c7f9fSRichard Henderson return true; 1256ee8c7f9fSRichard Henderson } 1257ee8c7f9fSRichard Henderson 1258e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set) 1259e6cb0354SRichard Henderson { 1260e6cb0354SRichard Henderson if (trap_userspace(dc, to_set)) { 1261e6cb0354SRichard Henderson return true; 1262e6cb0354SRichard Henderson } 12632a7567a2SRichard Henderson if (invalid_delay_slot(dc, "rts")) { 12642a7567a2SRichard Henderson return true; 12652a7567a2SRichard Henderson } 12662a7567a2SRichard Henderson 1267e6cb0354SRichard Henderson dc->tb_flags_to_set |= to_set; 1268e6cb0354SRichard Henderson setup_dslot(dc, true); 1269e6cb0354SRichard Henderson 1270e6cb0354SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 1271e6cb0354SRichard Henderson dc->jmp_dest = -1; 1272e6cb0354SRichard Henderson tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm); 1273e6cb0354SRichard Henderson return true; 1274e6cb0354SRichard Henderson } 1275e6cb0354SRichard Henderson 1276e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \ 1277e6cb0354SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \ 1278e6cb0354SRichard Henderson { return do_rts(dc, arg, IFLAG); } 1279e6cb0354SRichard Henderson 1280e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG) 1281e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG) 1282e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG) 1283e6cb0354SRichard Henderson DO_RTS(rtsd, 0) 1284e6cb0354SRichard Henderson 128520800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 128620800179SRichard Henderson { 128720800179SRichard Henderson /* If opcode_0_illegal, trap. */ 12884b893631SRichard Henderson if (dc->cfg->opcode_0_illegal) { 128920800179SRichard Henderson trap_illegal(dc, true); 129020800179SRichard Henderson return true; 129120800179SRichard Henderson } 129220800179SRichard Henderson /* 129320800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 129420800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 129520800179SRichard Henderson */ 129620800179SRichard Henderson return false; 1297fcf5ef2aSThomas Huth } 1298fcf5ef2aSThomas Huth 12991074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 1300fcf5ef2aSThomas Huth { 13011074c0fbSRichard Henderson TCGv_i32 t; 13021074c0fbSRichard Henderson 13031074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 13041074c0fbSRichard Henderson t = tcg_temp_new_i32(); 13051074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 13061074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 1307fcf5ef2aSThomas Huth } 1308fcf5ef2aSThomas Huth 1309536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) 1310536e340fSRichard Henderson { 1311536e340fSRichard Henderson uint32_t imm = arg->imm; 1312536e340fSRichard Henderson 1313536e340fSRichard Henderson if (trap_userspace(dc, imm != MSR_C)) { 1314536e340fSRichard Henderson return true; 1315536e340fSRichard Henderson } 1316536e340fSRichard Henderson 1317536e340fSRichard Henderson if (arg->rd) { 1318536e340fSRichard Henderson msr_read(dc, cpu_R[arg->rd]); 1319536e340fSRichard Henderson } 1320536e340fSRichard Henderson 1321536e340fSRichard Henderson /* 1322536e340fSRichard Henderson * Handle the carry bit separately. 1323536e340fSRichard Henderson * This is the only bit that userspace can modify. 1324536e340fSRichard Henderson */ 1325536e340fSRichard Henderson if (imm & MSR_C) { 1326536e340fSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, set); 1327536e340fSRichard Henderson } 1328536e340fSRichard Henderson 1329536e340fSRichard Henderson /* 1330536e340fSRichard Henderson * MSR_C and MSR_CC set above. 1331536e340fSRichard Henderson * MSR_PVR is not writable, and is always clear. 1332536e340fSRichard Henderson */ 1333536e340fSRichard Henderson imm &= ~(MSR_C | MSR_CC | MSR_PVR); 1334536e340fSRichard Henderson 1335536e340fSRichard Henderson if (imm != 0) { 1336536e340fSRichard Henderson if (set) { 1337536e340fSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, imm); 1338536e340fSRichard Henderson } else { 1339536e340fSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm); 1340536e340fSRichard Henderson } 134143b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 1342536e340fSRichard Henderson } 1343536e340fSRichard Henderson return true; 1344536e340fSRichard Henderson } 1345536e340fSRichard Henderson 1346536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg) 1347536e340fSRichard Henderson { 1348536e340fSRichard Henderson return do_msrclrset(dc, arg, false); 1349536e340fSRichard Henderson } 1350536e340fSRichard Henderson 1351536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) 1352536e340fSRichard Henderson { 1353536e340fSRichard Henderson return do_msrclrset(dc, arg, true); 1354536e340fSRichard Henderson } 1355536e340fSRichard Henderson 13569df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg) 1357fcf5ef2aSThomas Huth { 13589df297a2SRichard Henderson if (trap_userspace(dc, true)) { 13599df297a2SRichard Henderson return true; 1360f0f7e7f7SEdgar E. Iglesias } 1361f0f7e7f7SEdgar E. Iglesias 13629df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY 13639df297a2SRichard Henderson g_assert_not_reached(); 13649df297a2SRichard Henderson #else 13659df297a2SRichard Henderson if (arg->e && arg->rs != 0x1003) { 13669df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 13679df297a2SRichard Henderson "Invalid extended mts reg 0x%x\n", arg->rs); 13689df297a2SRichard Henderson return true; 13692023e9a3SEdgar E. Iglesias } 1370fcf5ef2aSThomas Huth 13719df297a2SRichard Henderson TCGv_i32 src = reg_for_read(dc, arg->ra); 13729df297a2SRichard Henderson switch (arg->rs) { 1373aa28e6d4SRichard Henderson case SR_MSR: 137443b34134SRichard Henderson /* Install MSR_C. */ 137543b34134SRichard Henderson tcg_gen_extract_i32(cpu_msr_c, src, 2, 1); 137643b34134SRichard Henderson /* 137743b34134SRichard Henderson * Clear MSR_C and MSR_CC; 137843b34134SRichard Henderson * MSR_PVR is not writable, and is always clear. 137943b34134SRichard Henderson */ 138043b34134SRichard Henderson tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR)); 1381fcf5ef2aSThomas Huth break; 13829df297a2SRichard Henderson case SR_FSR: 13839df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); 13849df297a2SRichard Henderson break; 13859df297a2SRichard Henderson case 0x800: 13869df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr)); 13879df297a2SRichard Henderson break; 13889df297a2SRichard Henderson case 0x802: 13899df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr)); 13909df297a2SRichard Henderson break; 13919df297a2SRichard Henderson 13929df297a2SRichard Henderson case 0x1000: /* PID */ 13939df297a2SRichard Henderson case 0x1001: /* ZPR */ 13949df297a2SRichard Henderson case 0x1002: /* TLBX */ 13959df297a2SRichard Henderson case 0x1003: /* TLBLO */ 13969df297a2SRichard Henderson case 0x1004: /* TLBHI */ 13979df297a2SRichard Henderson case 0x1005: /* TLBSX */ 13989df297a2SRichard Henderson { 1399*a5ea3dd7SRichard Henderson TCGv_i32 tmp_ext = tcg_constant_i32(arg->e); 1400*a5ea3dd7SRichard Henderson TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7); 14019df297a2SRichard Henderson 14029df297a2SRichard Henderson gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src); 14039df297a2SRichard Henderson } 14049df297a2SRichard Henderson break; 14059df297a2SRichard Henderson 14069df297a2SRichard Henderson default: 14079df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs); 14089df297a2SRichard Henderson return true; 14099df297a2SRichard Henderson } 141043b34134SRichard Henderson dc->base.is_jmp = DISAS_EXIT_NEXT; 14119df297a2SRichard Henderson return true; 14129df297a2SRichard Henderson #endif 14139df297a2SRichard Henderson } 14149df297a2SRichard Henderson 14159df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg) 14169df297a2SRichard Henderson { 14179df297a2SRichard Henderson TCGv_i32 dest = reg_for_write(dc, arg->rd); 14189df297a2SRichard Henderson 14199df297a2SRichard Henderson if (arg->e) { 14209df297a2SRichard Henderson switch (arg->rs) { 1421351527b7SEdgar E. Iglesias case SR_EAR: 1422dbdb77c4SRichard Henderson { 1423dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 14249df297a2SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14259df297a2SRichard Henderson tcg_gen_extrh_i64_i32(dest, t64); 1426dbdb77c4SRichard Henderson } 14279df297a2SRichard Henderson return true; 14289df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14299df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14309df297a2SRichard Henderson /* Handled below. */ 1431aa28e6d4SRichard Henderson break; 14329df297a2SRichard Henderson #endif 14339df297a2SRichard Henderson case 0x2006 ... 0x2009: 14349df297a2SRichard Henderson /* High bits of PVR6-9 not implemented. */ 14359df297a2SRichard Henderson tcg_gen_movi_i32(dest, 0); 14369df297a2SRichard Henderson return true; 1437fcf5ef2aSThomas Huth default: 14389df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 14399df297a2SRichard Henderson "Invalid extended mfs reg 0x%x\n", arg->rs); 14409df297a2SRichard Henderson return true; 1441fcf5ef2aSThomas Huth } 14429df297a2SRichard Henderson } 14439df297a2SRichard Henderson 14449df297a2SRichard Henderson switch (arg->rs) { 1445aa28e6d4SRichard Henderson case SR_PC: 14469df297a2SRichard Henderson tcg_gen_movi_i32(dest, dc->base.pc_next); 1447fcf5ef2aSThomas Huth break; 1448aa28e6d4SRichard Henderson case SR_MSR: 14499df297a2SRichard Henderson msr_read(dc, dest); 1450fcf5ef2aSThomas Huth break; 1451351527b7SEdgar E. Iglesias case SR_EAR: 1452dbdb77c4SRichard Henderson { 1453dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1454dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14559df297a2SRichard Henderson tcg_gen_extrl_i64_i32(dest, t64); 1456a1b48e3aSEdgar E. Iglesias } 1457aa28e6d4SRichard Henderson break; 1458351527b7SEdgar E. Iglesias case SR_ESR: 14599df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr)); 1460aa28e6d4SRichard Henderson break; 1461351527b7SEdgar E. Iglesias case SR_FSR: 14629df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr)); 1463aa28e6d4SRichard Henderson break; 1464351527b7SEdgar E. Iglesias case SR_BTR: 14659df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr)); 1466aa28e6d4SRichard Henderson break; 14677cdae31dSTong Ho case SR_EDR: 14689df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr)); 1469fcf5ef2aSThomas Huth break; 1470fcf5ef2aSThomas Huth case 0x800: 14719df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr)); 1472fcf5ef2aSThomas Huth break; 1473fcf5ef2aSThomas Huth case 0x802: 14749df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr)); 1475fcf5ef2aSThomas Huth break; 14769df297a2SRichard Henderson 14779df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14789df297a2SRichard Henderson case 0x1000: /* PID */ 14799df297a2SRichard Henderson case 0x1001: /* ZPR */ 14809df297a2SRichard Henderson case 0x1002: /* TLBX */ 14819df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14829df297a2SRichard Henderson case 0x1004: /* TLBHI */ 14839df297a2SRichard Henderson case 0x1005: /* TLBSX */ 14849df297a2SRichard Henderson { 1485*a5ea3dd7SRichard Henderson TCGv_i32 tmp_ext = tcg_constant_i32(arg->e); 1486*a5ea3dd7SRichard Henderson TCGv_i32 tmp_reg = tcg_constant_i32(arg->rs & 7); 14879df297a2SRichard Henderson 14889df297a2SRichard Henderson gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg); 14899df297a2SRichard Henderson } 14909df297a2SRichard Henderson break; 14919df297a2SRichard Henderson #endif 14929df297a2SRichard Henderson 1493351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 14949df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, 1495a4bcfc33SRichard Henderson offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000]) 1496a4bcfc33SRichard Henderson - offsetof(MicroBlazeCPU, env)); 1497fcf5ef2aSThomas Huth break; 1498fcf5ef2aSThomas Huth default: 14999df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs); 1500fcf5ef2aSThomas Huth break; 1501fcf5ef2aSThomas Huth } 15029df297a2SRichard Henderson return true; 1503fcf5ef2aSThomas Huth } 1504fcf5ef2aSThomas Huth 15053fb394fdSRichard Henderson static void do_rti(DisasContext *dc) 1506fcf5ef2aSThomas Huth { 15073fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1508fcf5ef2aSThomas Huth 15093fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15103fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE); 15113fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM); 15123fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM)); 15133fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1514fcf5ef2aSThomas Huth } 1515fcf5ef2aSThomas Huth 15163fb394fdSRichard Henderson static void do_rtb(DisasContext *dc) 1517fcf5ef2aSThomas Huth { 15183fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1519fcf5ef2aSThomas Huth 15203fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15213fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP)); 15223fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15233fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1524fcf5ef2aSThomas Huth } 1525fcf5ef2aSThomas Huth 15263fb394fdSRichard Henderson static void do_rte(DisasContext *dc) 1527fcf5ef2aSThomas Huth { 15283fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1529fcf5ef2aSThomas Huth 15303fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15313fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE); 15323fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15333fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP)); 15343fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1535fcf5ef2aSThomas Huth } 1536fcf5ef2aSThomas Huth 1537fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 153852065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl) 1539fcf5ef2aSThomas Huth { 1540fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1541fcf5ef2aSThomas Huth 1542bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 154352065d8fSRichard Henderson return true; 1544fcf5ef2aSThomas Huth } 1545fcf5ef2aSThomas Huth 1546cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 154752065d8fSRichard Henderson if (rb) { 154852065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 1549fcf5ef2aSThomas Huth } else { 155052065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 1551fcf5ef2aSThomas Huth } 1552fcf5ef2aSThomas Huth 1553*a5ea3dd7SRichard Henderson t_ctrl = tcg_constant_i32(ctrl); 155452065d8fSRichard Henderson gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl); 155552065d8fSRichard Henderson return true; 155652065d8fSRichard Henderson } 155752065d8fSRichard Henderson 155852065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg) 155952065d8fSRichard Henderson { 156052065d8fSRichard Henderson return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl); 156152065d8fSRichard Henderson } 156252065d8fSRichard Henderson 156352065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg) 156452065d8fSRichard Henderson { 156552065d8fSRichard Henderson return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl); 156652065d8fSRichard Henderson } 156752065d8fSRichard Henderson 156852065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl) 156952065d8fSRichard Henderson { 157052065d8fSRichard Henderson TCGv_i32 t_id, t_ctrl; 157152065d8fSRichard Henderson 157252065d8fSRichard Henderson if (trap_userspace(dc, true)) { 157352065d8fSRichard Henderson return true; 157452065d8fSRichard Henderson } 157552065d8fSRichard Henderson 157652065d8fSRichard Henderson t_id = tcg_temp_new_i32(); 157752065d8fSRichard Henderson if (rb) { 157852065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 157952065d8fSRichard Henderson } else { 158052065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 158152065d8fSRichard Henderson } 158252065d8fSRichard Henderson 1583*a5ea3dd7SRichard Henderson t_ctrl = tcg_constant_i32(ctrl); 158452065d8fSRichard Henderson gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra)); 158552065d8fSRichard Henderson return true; 158652065d8fSRichard Henderson } 158752065d8fSRichard Henderson 158852065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg) 158952065d8fSRichard Henderson { 159052065d8fSRichard Henderson return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl); 159152065d8fSRichard Henderson } 159252065d8fSRichard Henderson 159352065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg) 159452065d8fSRichard Henderson { 159552065d8fSRichard Henderson return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); 1596fcf5ef2aSThomas Huth } 1597fcf5ef2aSThomas Huth 1598372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1599fcf5ef2aSThomas Huth { 1600372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1601372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1602372122e3SRichard Henderson int bound; 1603fcf5ef2aSThomas Huth 16044b893631SRichard Henderson dc->cfg = &cpu->cfg; 1605683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags; 1606d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 160720800179SRichard Henderson dc->r0 = NULL; 160820800179SRichard Henderson dc->r0_set = false; 1609287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 1610b9c58aabSRichard Henderson dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; 1611b9c58aabSRichard Henderson dc->jmp_dest = -1; 1612fcf5ef2aSThomas Huth 1613372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1614372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1615fcf5ef2aSThomas Huth } 1616fcf5ef2aSThomas Huth 1617372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1618fcf5ef2aSThomas Huth { 1619fcf5ef2aSThomas Huth } 1620fcf5ef2aSThomas Huth 1621372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1622372122e3SRichard Henderson { 1623683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1624683a247eSRichard Henderson 1625683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); 1626683a247eSRichard Henderson dc->insn_start = tcg_last_op(); 1627372122e3SRichard Henderson } 1628fcf5ef2aSThomas Huth 1629372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1630372122e3SRichard Henderson { 1631372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1632372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 163344d1432bSRichard Henderson uint32_t ir; 1634372122e3SRichard Henderson 1635372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1636372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1637372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1638372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1639fcf5ef2aSThomas Huth } 1640fcf5ef2aSThomas Huth 16416f9642d7SRichard Henderson dc->tb_flags_to_set = 0; 16426f9642d7SRichard Henderson 164344d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 164444d1432bSRichard Henderson if (!decode(dc, ir)) { 1645921afa9dSRichard Henderson trap_illegal(dc, true); 164644d1432bSRichard Henderson } 164720800179SRichard Henderson 164820800179SRichard Henderson if (dc->r0) { 164920800179SRichard Henderson dc->r0 = NULL; 165020800179SRichard Henderson dc->r0_set = false; 165120800179SRichard Henderson } 165220800179SRichard Henderson 16536f9642d7SRichard Henderson /* Discard the imm global when its contents cannot be used. */ 16546f9642d7SRichard Henderson if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { 1655d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1656372122e3SRichard Henderson } 16576f9642d7SRichard Henderson 16581e521ce3SRichard Henderson dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG); 16596f9642d7SRichard Henderson dc->tb_flags |= dc->tb_flags_to_set; 1660d4705ae0SRichard Henderson dc->base.pc_next += 4; 1661fcf5ef2aSThomas Huth 1662b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { 16633d35bcc2SRichard Henderson /* 16643d35bcc2SRichard Henderson * Finish any return-from branch. 16653d35bcc2SRichard Henderson */ 16663c745866SRichard Henderson uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); 16673c745866SRichard Henderson if (unlikely(rt_ibe != 0)) { 16683c745866SRichard Henderson dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG); 16693c745866SRichard Henderson if (rt_ibe & DRTI_FLAG) { 1670fcf5ef2aSThomas Huth do_rti(dc); 16713c745866SRichard Henderson } else if (rt_ibe & DRTB_FLAG) { 1672fcf5ef2aSThomas Huth do_rtb(dc); 16733c745866SRichard Henderson } else { 1674fcf5ef2aSThomas Huth do_rte(dc); 1675372122e3SRichard Henderson } 16763c745866SRichard Henderson } 16773d35bcc2SRichard Henderson 16783d35bcc2SRichard Henderson /* Complete the branch, ending the TB. */ 16793d35bcc2SRichard Henderson switch (dc->base.is_jmp) { 16803d35bcc2SRichard Henderson case DISAS_NORETURN: 16813d35bcc2SRichard Henderson /* 16823d35bcc2SRichard Henderson * E.g. illegal insn in a delay slot. We've already exited 16833d35bcc2SRichard Henderson * and will handle D_FLAG in mb_cpu_do_interrupt. 16843d35bcc2SRichard Henderson */ 16853d35bcc2SRichard Henderson break; 16863d35bcc2SRichard Henderson case DISAS_NEXT: 16873c745866SRichard Henderson /* 16883c745866SRichard Henderson * Normal insn a delay slot. 16893c745866SRichard Henderson * However, the return-from-exception type insns should 16903c745866SRichard Henderson * return to the main loop, as they have adjusted MSR. 16913c745866SRichard Henderson */ 16923c745866SRichard Henderson dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP); 16933d35bcc2SRichard Henderson break; 16943d35bcc2SRichard Henderson case DISAS_EXIT_NEXT: 16953d35bcc2SRichard Henderson /* 16963d35bcc2SRichard Henderson * E.g. mts insn in a delay slot. Continue with btarget, 16973d35bcc2SRichard Henderson * but still return to the main loop. 16983d35bcc2SRichard Henderson */ 16993d35bcc2SRichard Henderson dc->base.is_jmp = DISAS_EXIT_JUMP; 17003d35bcc2SRichard Henderson break; 17013d35bcc2SRichard Henderson default: 17023d35bcc2SRichard Henderson g_assert_not_reached(); 17033d35bcc2SRichard Henderson } 1704372122e3SRichard Henderson } 1705372122e3SRichard Henderson } 1706372122e3SRichard Henderson 1707372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1708372122e3SRichard Henderson { 1709372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1710372122e3SRichard Henderson 1711372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1712372122e3SRichard Henderson /* We have already exited the TB. */ 1713372122e3SRichard Henderson return; 1714372122e3SRichard Henderson } 1715372122e3SRichard Henderson 1716372122e3SRichard Henderson t_sync_flags(dc); 1717372122e3SRichard Henderson 1718372122e3SRichard Henderson switch (dc->base.is_jmp) { 1719372122e3SRichard Henderson case DISAS_TOO_MANY: 1720372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1721372122e3SRichard Henderson return; 1722372122e3SRichard Henderson 172317e77796SRichard Henderson case DISAS_EXIT: 1724f6278ca9SRichard Henderson break; 1725f6278ca9SRichard Henderson case DISAS_EXIT_NEXT: 1726f6278ca9SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1727f6278ca9SRichard Henderson break; 1728f6278ca9SRichard Henderson case DISAS_EXIT_JUMP: 1729f6278ca9SRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1730f6278ca9SRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1731f6278ca9SRichard Henderson break; 1732372122e3SRichard Henderson 1733372122e3SRichard Henderson case DISAS_JUMP: 1734fbafb3a4SRichard Henderson if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) { 1735b9c58aabSRichard Henderson /* Direct jump. */ 1736b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1737b9c58aabSRichard Henderson 1738b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_ALWAYS) { 1739b9c58aabSRichard Henderson /* Conditional direct jump. */ 1740b9c58aabSRichard Henderson TCGLabel *taken = gen_new_label(); 1741b9c58aabSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1742b9c58aabSRichard Henderson 1743b9c58aabSRichard Henderson /* 1744b9c58aabSRichard Henderson * Copy bvalue to a temp now, so we can discard bvalue. 1745b9c58aabSRichard Henderson * This can avoid writing bvalue to memory when the 1746b9c58aabSRichard Henderson * delay slot cannot raise an exception. 1747b9c58aabSRichard Henderson */ 1748b9c58aabSRichard Henderson tcg_gen_mov_i32(tmp, cpu_bvalue); 1749b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_bvalue); 1750b9c58aabSRichard Henderson 1751b9c58aabSRichard Henderson tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken); 1752b9c58aabSRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1753b9c58aabSRichard Henderson gen_set_label(taken); 1754b9c58aabSRichard Henderson } 1755b9c58aabSRichard Henderson gen_goto_tb(dc, 0, dc->jmp_dest); 1756b9c58aabSRichard Henderson return; 1757b9c58aabSRichard Henderson } 1758b9c58aabSRichard Henderson 1759fbafb3a4SRichard Henderson /* Indirect jump (or direct jump w/ goto_tb disabled) */ 1760b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1761b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 17624059bd90SRichard Henderson tcg_gen_lookup_and_goto_ptr(); 1763372122e3SRichard Henderson return; 1764372122e3SRichard Henderson 1765a2b80dbdSRichard Henderson default: 1766a2b80dbdSRichard Henderson g_assert_not_reached(); 1767fcf5ef2aSThomas Huth } 1768f6278ca9SRichard Henderson 1769f6278ca9SRichard Henderson /* Finish DISAS_EXIT_* */ 1770f6278ca9SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1771f6278ca9SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1772f6278ca9SRichard Henderson } else { 1773f6278ca9SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1774f6278ca9SRichard Henderson } 1775fcf5ef2aSThomas Huth } 1776fcf5ef2aSThomas Huth 17778eb806a7SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, 17788eb806a7SRichard Henderson CPUState *cs, FILE *logfile) 1779372122e3SRichard Henderson { 17808eb806a7SRichard Henderson fprintf(logfile, "IN: %s\n", lookup_symbol(dcb->pc_first)); 17818eb806a7SRichard Henderson target_disas(logfile, cs, dcb->pc_first, dcb->tb->size); 1782fcf5ef2aSThomas Huth } 1783372122e3SRichard Henderson 1784372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1785372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1786372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1787372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1788372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1789372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1790372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1791372122e3SRichard Henderson }; 1792372122e3SRichard Henderson 1793597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns, 1794306c8721SRichard Henderson target_ulong pc, void *host_pc) 1795372122e3SRichard Henderson { 1796372122e3SRichard Henderson DisasContext dc; 1797306c8721SRichard Henderson translator_loop(cpu, tb, max_insns, pc, host_pc, &mb_tr_ops, &dc.base); 1798fcf5ef2aSThomas Huth } 1799fcf5ef2aSThomas Huth 180090c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1801fcf5ef2aSThomas Huth { 1802fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1803fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 18040c3da918SRichard Henderson uint32_t iflags; 1805fcf5ef2aSThomas Huth int i; 1806fcf5ef2aSThomas Huth 18070c3da918SRichard Henderson qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n", 18080c3da918SRichard Henderson env->pc, env->msr, 18092e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18102e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18112e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18122e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18130c3da918SRichard Henderson 18140c3da918SRichard Henderson iflags = env->iflags; 18150c3da918SRichard Henderson qemu_fprintf(f, "iflags: 0x%08x", iflags); 18160c3da918SRichard Henderson if (iflags & IMM_FLAG) { 18170c3da918SRichard Henderson qemu_fprintf(f, " IMM(0x%08x)", env->imm); 18182ead1b18SJoe Komlodi } 18190c3da918SRichard Henderson if (iflags & BIMM_FLAG) { 18200c3da918SRichard Henderson qemu_fprintf(f, " BIMM"); 18210c3da918SRichard Henderson } 18220c3da918SRichard Henderson if (iflags & D_FLAG) { 1823b9c58aabSRichard Henderson qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget); 18240c3da918SRichard Henderson } 18250c3da918SRichard Henderson if (iflags & DRTI_FLAG) { 18260c3da918SRichard Henderson qemu_fprintf(f, " DRTI"); 18270c3da918SRichard Henderson } 18280c3da918SRichard Henderson if (iflags & DRTE_FLAG) { 18290c3da918SRichard Henderson qemu_fprintf(f, " DRTE"); 18300c3da918SRichard Henderson } 18310c3da918SRichard Henderson if (iflags & DRTB_FLAG) { 18320c3da918SRichard Henderson qemu_fprintf(f, " DRTB"); 18330c3da918SRichard Henderson } 18340c3da918SRichard Henderson if (iflags & ESR_ESS_FLAG) { 18350c3da918SRichard Henderson qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK); 18362ead1b18SJoe Komlodi } 1837fcf5ef2aSThomas Huth 18380c3da918SRichard Henderson qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" 183919f27b6cSRichard Henderson "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n", 18400c3da918SRichard Henderson env->esr, env->fsr, env->btr, env->edr, 18410c3da918SRichard Henderson env->ear, env->slr, env->shr); 18420c3da918SRichard Henderson 18430c3da918SRichard Henderson for (i = 0; i < 32; i++) { 18440c3da918SRichard Henderson qemu_fprintf(f, "r%2.2d=%08x%c", 18450c3da918SRichard Henderson i, env->regs[i], i % 4 == 3 ? '\n' : ' '); 18460c3da918SRichard Henderson } 18470c3da918SRichard Henderson qemu_fprintf(f, "\n"); 1848fcf5ef2aSThomas Huth } 1849fcf5ef2aSThomas Huth 1850fcf5ef2aSThomas Huth void mb_tcg_init(void) 1851fcf5ef2aSThomas Huth { 1852480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1853480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1854fcf5ef2aSThomas Huth 1855480d29a8SRichard Henderson static const struct { 1856480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1857480d29a8SRichard Henderson } i32s[] = { 1858e47c2231SRichard Henderson /* 1859e47c2231SRichard Henderson * Note that r0 is handled specially in reg_for_read 1860e47c2231SRichard Henderson * and reg_for_write. Nothing should touch cpu_R[0]. 1861e47c2231SRichard Henderson * Leave that element NULL, which will assert quickly 1862e47c2231SRichard Henderson * inside the tcg generator functions. 1863e47c2231SRichard Henderson */ 1864e47c2231SRichard Henderson R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1865480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1866480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1867480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1868480d29a8SRichard Henderson 1869480d29a8SRichard Henderson SP(pc), 1870480d29a8SRichard Henderson SP(msr), 18711074c0fbSRichard Henderson SP(msr_c), 1872480d29a8SRichard Henderson SP(imm), 1873480d29a8SRichard Henderson SP(iflags), 1874b9c58aabSRichard Henderson SP(bvalue), 1875480d29a8SRichard Henderson SP(btarget), 1876480d29a8SRichard Henderson SP(res_val), 1877480d29a8SRichard Henderson }; 1878480d29a8SRichard Henderson 1879480d29a8SRichard Henderson #undef R 1880480d29a8SRichard Henderson #undef SP 1881480d29a8SRichard Henderson 1882480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1883480d29a8SRichard Henderson *i32s[i].var = 1884480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1885fcf5ef2aSThomas Huth } 188676e8187dSRichard Henderson 1887480d29a8SRichard Henderson cpu_res_addr = 1888480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1889fcf5ef2aSThomas Huth } 1890