1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * Xilinx MicroBlaze emulation for qemu: main translation routines. 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2009 Edgar E. Iglesias. 5fcf5ef2aSThomas Huth * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 6fcf5ef2aSThomas Huth * 7fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or 8fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public 9fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either 10fcf5ef2aSThomas Huth * version 2 of the License, or (at your option) any later version. 11fcf5ef2aSThomas Huth * 12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fcf5ef2aSThomas Huth * Lesser General Public License for more details. 16fcf5ef2aSThomas Huth * 17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fcf5ef2aSThomas Huth */ 20fcf5ef2aSThomas Huth 21fcf5ef2aSThomas Huth #include "qemu/osdep.h" 22fcf5ef2aSThomas Huth #include "cpu.h" 23fcf5ef2aSThomas Huth #include "disas/disas.h" 24fcf5ef2aSThomas Huth #include "exec/exec-all.h" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 26fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 27fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h" 28fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 2977fc6f5eSLluís Vilanova #include "exec/translator.h" 3090c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 31fcf5ef2aSThomas Huth 32fcf5ef2aSThomas Huth #include "trace-tcg.h" 33fcf5ef2aSThomas Huth #include "exec/log.h" 34fcf5ef2aSThomas Huth 35fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 36fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 37fcf5ef2aSThomas Huth 3877fc6f5eSLluís Vilanova /* is_jmp field values */ 3977fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 4077fc6f5eSLluís Vilanova #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ 4177fc6f5eSLluís Vilanova 42cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 430f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 443e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 451074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 469b158558SRichard Henderson static TCGv_i32 cpu_imm; 47b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue; 480f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 499b158558SRichard Henderson static TCGv_i32 cpu_iflags; 509b158558SRichard Henderson static TCGv cpu_res_addr; 519b158558SRichard Henderson static TCGv_i32 cpu_res_val; 52fcf5ef2aSThomas Huth 53fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 54fcf5ef2aSThomas Huth 55fcf5ef2aSThomas Huth /* This is the state at translation time. */ 56fcf5ef2aSThomas Huth typedef struct DisasContext { 57d4705ae0SRichard Henderson DisasContextBase base; 58fcf5ef2aSThomas Huth MicroBlazeCPU *cpu; 59fcf5ef2aSThomas Huth 60683a247eSRichard Henderson /* TCG op of the current insn_start. */ 61683a247eSRichard Henderson TCGOp *insn_start; 62683a247eSRichard Henderson 6320800179SRichard Henderson TCGv_i32 r0; 6420800179SRichard Henderson bool r0_set; 6520800179SRichard Henderson 66fcf5ef2aSThomas Huth /* Decoder. */ 67d7ecb757SRichard Henderson uint32_t ext_imm; 68fcf5ef2aSThomas Huth unsigned int cpustate_changed; 69683a247eSRichard Henderson unsigned int tb_flags; 706f9642d7SRichard Henderson unsigned int tb_flags_to_set; 71287b1defSRichard Henderson int mem_index; 72fcf5ef2aSThomas Huth 73b9c58aabSRichard Henderson /* Condition under which to jump, including NEVER and ALWAYS. */ 74b9c58aabSRichard Henderson TCGCond jmp_cond; 75b9c58aabSRichard Henderson 76b9c58aabSRichard Henderson /* Immediate branch-taken destination, or -1 for indirect. */ 77b9c58aabSRichard Henderson uint32_t jmp_dest; 78fcf5ef2aSThomas Huth } DisasContext; 79fcf5ef2aSThomas Huth 8020800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8120800179SRichard Henderson { 8220800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 8320800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 8420800179SRichard Henderson } 8520800179SRichard Henderson return x; 8620800179SRichard Henderson } 8720800179SRichard Henderson 8844d1432bSRichard Henderson /* Include the auto-generated decoder. */ 8944d1432bSRichard Henderson #include "decode-insns.c.inc" 9044d1432bSRichard Henderson 91683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc) 92fcf5ef2aSThomas Huth { 93fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 94683a247eSRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) { 95683a247eSRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK); 96fcf5ef2aSThomas Huth } 97fcf5ef2aSThomas Huth } 98fcf5ef2aSThomas Huth 9941ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 100fcf5ef2aSThomas Huth { 101fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 102fcf5ef2aSThomas Huth 103fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 104fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 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 { 11741ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 11841ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 11941ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12041ba37c4SRichard Henderson 12141ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 12241ba37c4SRichard Henderson } 12341ba37c4SRichard Henderson 124fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 125fcf5ef2aSThomas Huth { 126fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 127d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 128fcf5ef2aSThomas Huth #else 129fcf5ef2aSThomas Huth return true; 130fcf5ef2aSThomas Huth #endif 131fcf5ef2aSThomas Huth } 132fcf5ef2aSThomas Huth 133fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 134fcf5ef2aSThomas Huth { 135d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1360b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1370b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1380b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1390b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1400b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 141fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1420f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 143d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 144fcf5ef2aSThomas Huth } else { 1450f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 14607ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 147fcf5ef2aSThomas Huth } 148d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 149fcf5ef2aSThomas Huth } 150fcf5ef2aSThomas Huth 151bdfc1e88SEdgar E. Iglesias /* 1529ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1539ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1549ba8cd45SEdgar E. Iglesias */ 1559ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1569ba8cd45SEdgar E. Iglesias { 1572c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE) 1585143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 15941ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1609ba8cd45SEdgar E. Iglesias } 1619ba8cd45SEdgar E. Iglesias return cond; 1629ba8cd45SEdgar E. Iglesias } 1639ba8cd45SEdgar E. Iglesias 1649ba8cd45SEdgar E. Iglesias /* 165bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 166bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 167bdfc1e88SEdgar E. Iglesias */ 168bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 169bdfc1e88SEdgar E. Iglesias { 170287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX; 171bdfc1e88SEdgar E. Iglesias 1722c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) { 17341ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 174bdfc1e88SEdgar E. Iglesias } 175bdfc1e88SEdgar E. Iglesias return cond_user; 176bdfc1e88SEdgar E. Iglesias } 177bdfc1e88SEdgar E. Iglesias 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); 26120800179SRichard Henderson imm = tcg_const_i32(arg->imm); 26220800179SRichard Henderson 26320800179SRichard Henderson fn(rd, ra, imm); 26420800179SRichard Henderson 26520800179SRichard Henderson tcg_temp_free_i32(imm); 26620800179SRichard Henderson return true; 26720800179SRichard Henderson } 26820800179SRichard Henderson 26920800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 27020800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 27120800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 27220800179SRichard Henderson 273607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 274607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 275607f5767SRichard Henderson { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } 276607f5767SRichard Henderson 27739cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 27839cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 27939cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 28039cf3864SRichard Henderson 28139cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 28239cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 28339cf3864SRichard Henderson { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); } 28439cf3864SRichard Henderson 28520800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 28620800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 28720800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 28820800179SRichard Henderson 28997955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 29097955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29197955cebSRichard Henderson { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } 29297955cebSRichard Henderson 29320800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 29420800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29520800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 29620800179SRichard Henderson 297d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 298d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 299d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 300d5aead3dSRichard Henderson 301d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 302d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 303d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 304d5aead3dSRichard Henderson 30520800179SRichard Henderson /* No input carry, but output carry. */ 30620800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 30720800179SRichard Henderson { 30820800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 30920800179SRichard Henderson 31020800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 31120800179SRichard Henderson 31220800179SRichard Henderson tcg_temp_free_i32(zero); 31320800179SRichard Henderson } 31420800179SRichard Henderson 31520800179SRichard Henderson /* Input and output carry. */ 31620800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 31720800179SRichard Henderson { 31820800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 31920800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 32020800179SRichard Henderson 32120800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 32220800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 32320800179SRichard Henderson 32420800179SRichard Henderson tcg_temp_free_i32(tmp); 32520800179SRichard Henderson tcg_temp_free_i32(zero); 32620800179SRichard Henderson } 32720800179SRichard Henderson 32820800179SRichard Henderson /* Input carry, but no output carry. */ 32920800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 33020800179SRichard Henderson { 33120800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 33220800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 33320800179SRichard Henderson } 33420800179SRichard Henderson 33520800179SRichard Henderson DO_TYPEA(add, true, gen_add) 33620800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 33720800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 33820800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 33920800179SRichard Henderson 34020800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 34120800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 34220800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 34320800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 34420800179SRichard Henderson 345cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 346cb0a0a4cSRichard Henderson { 347cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 348cb0a0a4cSRichard Henderson } 349cb0a0a4cSRichard Henderson 350cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 351cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 352cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 353cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 354cb0a0a4cSRichard Henderson 355081d8e02SRichard Henderson static void gen_bsra(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_sar_i32(out, ina, tmp); 360081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 361081d8e02SRichard Henderson } 362081d8e02SRichard Henderson 363081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 364081d8e02SRichard Henderson { 365081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 366081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 367081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 368081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 369081d8e02SRichard Henderson } 370081d8e02SRichard Henderson 371081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 372081d8e02SRichard Henderson { 373081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 374081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 375081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 376081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 377081d8e02SRichard Henderson } 378081d8e02SRichard Henderson 379081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 380081d8e02SRichard Henderson { 381081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 382081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 383081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 384081d8e02SRichard Henderson 385081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 386081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 387081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 388081d8e02SRichard Henderson imm_w, imm_s); 389081d8e02SRichard Henderson } else { 390081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 391081d8e02SRichard Henderson } 392081d8e02SRichard Henderson } 393081d8e02SRichard Henderson 394081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 395081d8e02SRichard Henderson { 396081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 397081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 398081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 399081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 400081d8e02SRichard Henderson 401081d8e02SRichard Henderson if (imm_w < imm_s) { 402081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 403081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 404081d8e02SRichard Henderson imm_w, imm_s); 405081d8e02SRichard Henderson } else { 406081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 407081d8e02SRichard Henderson } 408081d8e02SRichard Henderson } 409081d8e02SRichard Henderson 410081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 411081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 412081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 413081d8e02SRichard Henderson 414081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 415081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 416081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 417081d8e02SRichard Henderson 418081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 419081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 420081d8e02SRichard Henderson 42139cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 42239cf3864SRichard Henderson { 42339cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 42439cf3864SRichard Henderson } 42539cf3864SRichard Henderson 42639cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 42739cf3864SRichard Henderson 42858b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 42958b48b63SRichard Henderson { 43058b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 43158b48b63SRichard Henderson 43258b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 43358b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 43458b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 43558b48b63SRichard Henderson tcg_temp_free_i32(lt); 43658b48b63SRichard Henderson } 43758b48b63SRichard Henderson 43858b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 43958b48b63SRichard Henderson { 44058b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 44158b48b63SRichard Henderson 44258b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 44358b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 44458b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 44558b48b63SRichard Henderson tcg_temp_free_i32(lt); 44658b48b63SRichard Henderson } 44758b48b63SRichard Henderson 44858b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 44958b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 450a2b0b90eSRichard Henderson 451d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 452d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 453d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 454d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 455d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 456d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 457d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 458d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 459d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 460d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 461d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 462d5aead3dSRichard Henderson 463d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 464d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 465d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 466d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 467d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 468d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 469d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 470d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 471d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 472d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 473d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 474d5aead3dSRichard Henderson 475d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 476d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 477d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 478d5aead3dSRichard Henderson 479d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 480d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 481d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 482d5aead3dSRichard Henderson 483d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 484b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 485b1354342SRichard Henderson { 486b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 487b1354342SRichard Henderson } 488b1354342SRichard Henderson 489b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 490b1354342SRichard Henderson { 491b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 492b1354342SRichard Henderson } 493b1354342SRichard Henderson 494b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 495b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 496b1354342SRichard Henderson 497e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 498e64b2e5cSRichard Henderson { 499e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 500e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 5016f9642d7SRichard Henderson dc->tb_flags_to_set = IMM_FLAG; 502e64b2e5cSRichard Henderson return true; 503e64b2e5cSRichard Henderson } 504e64b2e5cSRichard Henderson 50597955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 50697955cebSRichard Henderson { 50797955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 50897955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 50997955cebSRichard Henderson tcg_temp_free_i32(tmp); 51097955cebSRichard Henderson } 51197955cebSRichard Henderson 51297955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 51397955cebSRichard Henderson { 51497955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 51597955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 51697955cebSRichard Henderson tcg_temp_free_i32(tmp); 51797955cebSRichard Henderson } 51897955cebSRichard Henderson 51997955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 52097955cebSRichard Henderson { 52197955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 52297955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 52397955cebSRichard Henderson tcg_temp_free_i32(tmp); 52497955cebSRichard Henderson } 52597955cebSRichard Henderson 52697955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 52797955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 52897955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 52997955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 53097955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 53197955cebSRichard Henderson 532cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 533cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 534cb0a0a4cSRichard Henderson 535607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 536607f5767SRichard Henderson { 537607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 538607f5767SRichard Henderson } 539607f5767SRichard Henderson 540607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 541607f5767SRichard Henderson { 542607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 543607f5767SRichard Henderson } 544607f5767SRichard Henderson 545607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 546607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 547607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 548607f5767SRichard Henderson 549a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 550a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 551a2b0b90eSRichard Henderson { 552a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 553a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 554a2b0b90eSRichard Henderson } 555a2b0b90eSRichard Henderson 556a2b0b90eSRichard Henderson /* Input and output carry. */ 557a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 558a2b0b90eSRichard Henderson { 559a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 560a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 561a2b0b90eSRichard Henderson 562a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 563a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 564a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 565a2b0b90eSRichard Henderson 566a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 567a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 568a2b0b90eSRichard Henderson } 569a2b0b90eSRichard Henderson 570a2b0b90eSRichard Henderson /* No input or output carry. */ 571a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 572a2b0b90eSRichard Henderson { 573a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 574a2b0b90eSRichard Henderson } 575a2b0b90eSRichard Henderson 576a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 577a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 578a2b0b90eSRichard Henderson { 579a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 580a2b0b90eSRichard Henderson 581a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 582a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 583a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 584a2b0b90eSRichard Henderson 585a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 586a2b0b90eSRichard Henderson } 587a2b0b90eSRichard Henderson 588a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 589a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 590a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 591a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 592a2b0b90eSRichard Henderson 593a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 594a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 595a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 596a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 597a2b0b90eSRichard Henderson 59839cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 59939cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 60039cf3864SRichard Henderson 60139cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 60239cf3864SRichard Henderson { 60339cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 60439cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 60539cf3864SRichard Henderson } 60639cf3864SRichard Henderson 60739cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 60839cf3864SRichard Henderson { 60939cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 61039cf3864SRichard Henderson 61139cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 61239cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 61339cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 61439cf3864SRichard Henderson 61539cf3864SRichard Henderson tcg_temp_free_i32(tmp); 61639cf3864SRichard Henderson } 61739cf3864SRichard Henderson 61839cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 61939cf3864SRichard Henderson { 62039cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 62139cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 62239cf3864SRichard Henderson } 62339cf3864SRichard Henderson 62439cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 62539cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 62639cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 62739cf3864SRichard Henderson 62839cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 62939cf3864SRichard Henderson { 63039cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 63139cf3864SRichard Henderson } 63239cf3864SRichard Henderson 63339cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 63439cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 63539cf3864SRichard Henderson 63639cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 63739cf3864SRichard Henderson { 63839cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 63939cf3864SRichard Henderson trap_userspace(dc, true); 64039cf3864SRichard Henderson return true; 64139cf3864SRichard Henderson } 64239cf3864SRichard Henderson 643cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 644cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 645cb0a0a4cSRichard Henderson 646d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 647d8e59c4aSRichard Henderson { 648d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 649d8e59c4aSRichard Henderson 650d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 651d8e59c4aSRichard Henderson if (ra && rb) { 652d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 653d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 654d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 655d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 656d8e59c4aSRichard Henderson } else if (ra) { 657d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 658d8e59c4aSRichard Henderson } else if (rb) { 659d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 660d8e59c4aSRichard Henderson } else { 661d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 662d8e59c4aSRichard Henderson } 663d8e59c4aSRichard Henderson 664d8e59c4aSRichard Henderson if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) { 665d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 666d8e59c4aSRichard Henderson } 667d8e59c4aSRichard Henderson return ret; 668d8e59c4aSRichard Henderson } 669d8e59c4aSRichard Henderson 670d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 671d8e59c4aSRichard Henderson { 672d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 673d8e59c4aSRichard Henderson 674d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 675d8e59c4aSRichard Henderson if (ra) { 676d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 677d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 678d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 679d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 680d8e59c4aSRichard Henderson } else { 681d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 682d8e59c4aSRichard Henderson } 683d8e59c4aSRichard Henderson 684d8e59c4aSRichard Henderson if (ra == 1 && dc->cpu->cfg.stackprot) { 685d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 686d8e59c4aSRichard Henderson } 687d8e59c4aSRichard Henderson return ret; 688d8e59c4aSRichard Henderson } 689d8e59c4aSRichard Henderson 690d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 691d8e59c4aSRichard Henderson { 692d8e59c4aSRichard Henderson int addr_size = dc->cpu->cfg.addr_size; 693d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 694d8e59c4aSRichard Henderson 695d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 696d8e59c4aSRichard Henderson if (rb) { 697d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 698d8e59c4aSRichard Henderson } else { 699d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 700d8e59c4aSRichard Henderson } 701d8e59c4aSRichard Henderson } else { 702d8e59c4aSRichard Henderson if (rb) { 703d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 704d8e59c4aSRichard Henderson } else { 705d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 706d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 707d8e59c4aSRichard Henderson } 708d8e59c4aSRichard Henderson if (addr_size < 64) { 709d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 710d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 711d8e59c4aSRichard Henderson } 712d8e59c4aSRichard Henderson } 713d8e59c4aSRichard Henderson return ret; 714d8e59c4aSRichard Henderson } 715d8e59c4aSRichard Henderson 716ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd, 717ab0c8d0fSRichard Henderson MemOp size, bool store) 718ab0c8d0fSRichard Henderson { 719ab0c8d0fSRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); 720ab0c8d0fSRichard Henderson 721ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG; 722ab0c8d0fSRichard Henderson iflags |= rd << 5; 723ab0c8d0fSRichard Henderson iflags |= store * ESR_S; 724ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W; 725ab0c8d0fSRichard Henderson 726ab0c8d0fSRichard Henderson tcg_set_insn_start_param(dc->insn_start, 1, iflags); 727ab0c8d0fSRichard Henderson } 728ab0c8d0fSRichard Henderson 729d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 730d8e59c4aSRichard Henderson int mem_index, bool rev) 731d8e59c4aSRichard Henderson { 732d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 733d8e59c4aSRichard Henderson 734d8e59c4aSRichard Henderson /* 735d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 736d8e59c4aSRichard Henderson * 737d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 738d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 739d8e59c4aSRichard Henderson */ 740d8e59c4aSRichard Henderson if (rev) { 741d8e59c4aSRichard Henderson if (size > MO_8) { 742d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 743d8e59c4aSRichard Henderson } 744d8e59c4aSRichard Henderson if (size < MO_32) { 745d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 746d8e59c4aSRichard Henderson } 747d8e59c4aSRichard Henderson } 748d8e59c4aSRichard Henderson 749ab0c8d0fSRichard Henderson if (size > MO_8 && 750ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 751ab0c8d0fSRichard Henderson dc->cpu->cfg.unaligned_exceptions) { 752ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false); 753ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 754d8e59c4aSRichard Henderson } 755d8e59c4aSRichard Henderson 756ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); 757d8e59c4aSRichard Henderson 758d8e59c4aSRichard Henderson tcg_temp_free(addr); 759d8e59c4aSRichard Henderson return true; 760d8e59c4aSRichard Henderson } 761d8e59c4aSRichard Henderson 762d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 763d8e59c4aSRichard Henderson { 764d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 765d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 766d8e59c4aSRichard Henderson } 767d8e59c4aSRichard Henderson 768d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 769d8e59c4aSRichard Henderson { 770d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 771d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 772d8e59c4aSRichard Henderson } 773d8e59c4aSRichard Henderson 774d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 775d8e59c4aSRichard Henderson { 776d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 777d8e59c4aSRichard Henderson return true; 778d8e59c4aSRichard Henderson } 779d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 780d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 781d8e59c4aSRichard Henderson } 782d8e59c4aSRichard Henderson 783d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 784d8e59c4aSRichard Henderson { 785d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 786d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 787d8e59c4aSRichard Henderson } 788d8e59c4aSRichard Henderson 789d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 790d8e59c4aSRichard Henderson { 791d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 792d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 793d8e59c4aSRichard Henderson } 794d8e59c4aSRichard Henderson 795d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 796d8e59c4aSRichard Henderson { 797d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 798d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 799d8e59c4aSRichard Henderson } 800d8e59c4aSRichard Henderson 801d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 802d8e59c4aSRichard Henderson { 803d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 804d8e59c4aSRichard Henderson return true; 805d8e59c4aSRichard Henderson } 806d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 807d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 808d8e59c4aSRichard Henderson } 809d8e59c4aSRichard Henderson 810d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 811d8e59c4aSRichard Henderson { 812d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 813d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 814d8e59c4aSRichard Henderson } 815d8e59c4aSRichard Henderson 816d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 817d8e59c4aSRichard Henderson { 818d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 819d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 820d8e59c4aSRichard Henderson } 821d8e59c4aSRichard Henderson 822d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 823d8e59c4aSRichard Henderson { 824d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 825d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 826d8e59c4aSRichard Henderson } 827d8e59c4aSRichard Henderson 828d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 829d8e59c4aSRichard Henderson { 830d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 831d8e59c4aSRichard Henderson return true; 832d8e59c4aSRichard Henderson } 833d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 834d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 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 tcg_temp_free(addr); 853d8e59c4aSRichard Henderson 854d8e59c4aSRichard Henderson if (arg->rd) { 855d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 856d8e59c4aSRichard Henderson } 857d8e59c4aSRichard Henderson 858d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 859d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 860d8e59c4aSRichard Henderson return true; 861d8e59c4aSRichard Henderson } 862d8e59c4aSRichard Henderson 863d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 864d8e59c4aSRichard Henderson int mem_index, bool rev) 865d8e59c4aSRichard Henderson { 866d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 867d8e59c4aSRichard Henderson 868d8e59c4aSRichard Henderson /* 869d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 870d8e59c4aSRichard Henderson * 871d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 872d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 873d8e59c4aSRichard Henderson */ 874d8e59c4aSRichard Henderson if (rev) { 875d8e59c4aSRichard Henderson if (size > MO_8) { 876d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 877d8e59c4aSRichard Henderson } 878d8e59c4aSRichard Henderson if (size < MO_32) { 879d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 880d8e59c4aSRichard Henderson } 881d8e59c4aSRichard Henderson } 882d8e59c4aSRichard Henderson 883ab0c8d0fSRichard Henderson if (size > MO_8 && 884ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 885ab0c8d0fSRichard Henderson dc->cpu->cfg.unaligned_exceptions) { 886ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true); 887ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 888d8e59c4aSRichard Henderson } 889d8e59c4aSRichard Henderson 890ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 891ab0c8d0fSRichard Henderson 892d8e59c4aSRichard Henderson tcg_temp_free(addr); 893d8e59c4aSRichard Henderson return true; 894d8e59c4aSRichard Henderson } 895d8e59c4aSRichard Henderson 896d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 897d8e59c4aSRichard Henderson { 898d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 899d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 900d8e59c4aSRichard Henderson } 901d8e59c4aSRichard Henderson 902d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 903d8e59c4aSRichard Henderson { 904d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 905d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 906d8e59c4aSRichard Henderson } 907d8e59c4aSRichard Henderson 908d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 909d8e59c4aSRichard Henderson { 910d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 911d8e59c4aSRichard Henderson return true; 912d8e59c4aSRichard Henderson } 913d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 914d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 915d8e59c4aSRichard Henderson } 916d8e59c4aSRichard Henderson 917d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 918d8e59c4aSRichard Henderson { 919d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 920d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 921d8e59c4aSRichard Henderson } 922d8e59c4aSRichard Henderson 923d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg) 924d8e59c4aSRichard Henderson { 925d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 926d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 927d8e59c4aSRichard Henderson } 928d8e59c4aSRichard Henderson 929d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 930d8e59c4aSRichard Henderson { 931d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 932d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 933d8e59c4aSRichard Henderson } 934d8e59c4aSRichard Henderson 935d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 936d8e59c4aSRichard Henderson { 937d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 938d8e59c4aSRichard Henderson return true; 939d8e59c4aSRichard Henderson } 940d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 941d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 942d8e59c4aSRichard Henderson } 943d8e59c4aSRichard Henderson 944d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 945d8e59c4aSRichard Henderson { 946d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 947d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 948d8e59c4aSRichard Henderson } 949d8e59c4aSRichard Henderson 950d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 951d8e59c4aSRichard Henderson { 952d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 953d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 954d8e59c4aSRichard Henderson } 955d8e59c4aSRichard Henderson 956d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 957d8e59c4aSRichard Henderson { 958d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 959d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 960d8e59c4aSRichard Henderson } 961d8e59c4aSRichard Henderson 962d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 963d8e59c4aSRichard Henderson { 964d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 965d8e59c4aSRichard Henderson return true; 966d8e59c4aSRichard Henderson } 967d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 968d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 969d8e59c4aSRichard Henderson } 970d8e59c4aSRichard Henderson 971d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 972d8e59c4aSRichard Henderson { 973d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 974d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 975d8e59c4aSRichard Henderson } 976d8e59c4aSRichard Henderson 977d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 978d8e59c4aSRichard Henderson { 979d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 980d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 981d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 982d8e59c4aSRichard Henderson TCGv_i32 tval; 983d8e59c4aSRichard Henderson 984d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 985d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 986d8e59c4aSRichard Henderson 987d8e59c4aSRichard Henderson /* 988d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 989d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 990d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 991d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 992d8e59c4aSRichard Henderson */ 993d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 994d8e59c4aSRichard Henderson tcg_temp_free(addr); 995d8e59c4aSRichard Henderson 996d8e59c4aSRichard Henderson /* 997d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 998d8e59c4aSRichard Henderson * the reserved location. 999d8e59c4aSRichard Henderson */ 1000d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1001d8e59c4aSRichard Henderson 1002d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1003d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1004d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1005d8e59c4aSRichard Henderson 1006d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1007d8e59c4aSRichard Henderson tcg_temp_free_i32(tval); 1008d8e59c4aSRichard Henderson 1009d8e59c4aSRichard Henderson /* Success */ 1010d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1011d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1012d8e59c4aSRichard Henderson 1013d8e59c4aSRichard Henderson /* Failure */ 1014d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1015d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1016d8e59c4aSRichard Henderson 1017d8e59c4aSRichard Henderson gen_set_label(swx_done); 1018d8e59c4aSRichard Henderson 1019d8e59c4aSRichard Henderson /* 1020d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1021d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1022d8e59c4aSRichard Henderson */ 1023d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1024d8e59c4aSRichard Henderson return true; 1025d8e59c4aSRichard Henderson } 1026d8e59c4aSRichard Henderson 102716bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b) 102816bbbbc9SRichard Henderson { 102916bbbbc9SRichard Henderson dc->tb_flags_to_set |= D_FLAG; 103016bbbbc9SRichard Henderson if (type_b && (dc->tb_flags & IMM_FLAG)) { 103116bbbbc9SRichard Henderson dc->tb_flags_to_set |= BIMM_FLAG; 103216bbbbc9SRichard Henderson } 103316bbbbc9SRichard Henderson } 103416bbbbc9SRichard Henderson 103516bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm, 103616bbbbc9SRichard Henderson bool delay, bool abs, int link) 103716bbbbc9SRichard Henderson { 103816bbbbc9SRichard Henderson uint32_t add_pc; 103916bbbbc9SRichard Henderson 104016bbbbc9SRichard Henderson if (delay) { 104116bbbbc9SRichard Henderson setup_dslot(dc, dest_rb < 0); 104216bbbbc9SRichard Henderson } 104316bbbbc9SRichard Henderson 104416bbbbc9SRichard Henderson if (link) { 104516bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next); 104616bbbbc9SRichard Henderson } 104716bbbbc9SRichard Henderson 104816bbbbc9SRichard Henderson /* Store the branch taken destination into btarget. */ 104916bbbbc9SRichard Henderson add_pc = abs ? 0 : dc->base.pc_next; 105016bbbbc9SRichard Henderson if (dest_rb > 0) { 105116bbbbc9SRichard Henderson dc->jmp_dest = -1; 105216bbbbc9SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc); 105316bbbbc9SRichard Henderson } else { 105416bbbbc9SRichard Henderson dc->jmp_dest = add_pc + dest_imm; 105516bbbbc9SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 105616bbbbc9SRichard Henderson } 105716bbbbc9SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 105816bbbbc9SRichard Henderson return true; 105916bbbbc9SRichard Henderson } 106016bbbbc9SRichard Henderson 106116bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK) \ 106216bbbbc9SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg) \ 106316bbbbc9SRichard Henderson { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); } \ 106416bbbbc9SRichard Henderson static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg) \ 106516bbbbc9SRichard Henderson { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); } 106616bbbbc9SRichard Henderson 106716bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false) 106816bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false) 106916bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false) 107016bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false) 107116bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true) 107216bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true) 107316bbbbc9SRichard Henderson 1074fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm, 1075fd779113SRichard Henderson TCGCond cond, int ra, bool delay) 1076fd779113SRichard Henderson { 1077fd779113SRichard Henderson TCGv_i32 zero, next; 1078fd779113SRichard Henderson 1079fd779113SRichard Henderson if (delay) { 1080fd779113SRichard Henderson setup_dslot(dc, dest_rb < 0); 1081fd779113SRichard Henderson } 1082fd779113SRichard Henderson 1083fd779113SRichard Henderson dc->jmp_cond = cond; 1084fd779113SRichard Henderson 1085fd779113SRichard Henderson /* Cache the condition register in cpu_bvalue across any delay slot. */ 1086fd779113SRichard Henderson tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra)); 1087fd779113SRichard Henderson 1088fd779113SRichard Henderson /* Store the branch taken destination into btarget. */ 1089fd779113SRichard Henderson if (dest_rb > 0) { 1090fd779113SRichard Henderson dc->jmp_dest = -1; 1091fd779113SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next); 1092fd779113SRichard Henderson } else { 1093fd779113SRichard Henderson dc->jmp_dest = dc->base.pc_next + dest_imm; 1094fd779113SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 1095fd779113SRichard Henderson } 1096fd779113SRichard Henderson 1097fd779113SRichard Henderson /* Compute the final destination into btarget. */ 1098fd779113SRichard Henderson zero = tcg_const_i32(0); 1099fd779113SRichard Henderson next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4); 1100fd779113SRichard Henderson tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, 1101fd779113SRichard Henderson reg_for_read(dc, ra), zero, 1102fd779113SRichard Henderson cpu_btarget, next); 1103fd779113SRichard Henderson tcg_temp_free_i32(zero); 1104fd779113SRichard Henderson tcg_temp_free_i32(next); 1105fd779113SRichard Henderson 1106fd779113SRichard Henderson return true; 1107fd779113SRichard Henderson } 1108fd779113SRichard Henderson 1109fd779113SRichard Henderson #define DO_BCC(NAME, COND) \ 1110fd779113SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg) \ 1111fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); } \ 1112fd779113SRichard Henderson static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg) \ 1113fd779113SRichard Henderson { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); } \ 1114fd779113SRichard Henderson static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg) \ 1115fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); } \ 1116fd779113SRichard Henderson static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg) \ 1117fd779113SRichard Henderson { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); } 1118fd779113SRichard Henderson 1119fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ) 1120fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE) 1121fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT) 1122fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE) 1123fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT) 1124fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE) 1125fd779113SRichard Henderson 1126f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg) 1127f5235314SRichard Henderson { 1128f5235314SRichard Henderson if (trap_userspace(dc, true)) { 1129f5235314SRichard Henderson return true; 1130f5235314SRichard Henderson } 1131f5235314SRichard Henderson tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb)); 1132f5235314SRichard Henderson if (arg->rd) { 1133f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1134f5235314SRichard Henderson } 1135f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP); 1136f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1137f5235314SRichard Henderson 1138f5235314SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1139f5235314SRichard Henderson return true; 1140f5235314SRichard Henderson } 1141f5235314SRichard Henderson 1142f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) 1143f5235314SRichard Henderson { 1144f5235314SRichard Henderson uint32_t imm = arg->imm; 1145f5235314SRichard Henderson 1146f5235314SRichard Henderson if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) { 1147f5235314SRichard Henderson return true; 1148f5235314SRichard Henderson } 1149f5235314SRichard Henderson tcg_gen_movi_i32(cpu_pc, imm); 1150f5235314SRichard Henderson if (arg->rd) { 1151f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1152f5235314SRichard Henderson } 1153f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1154f5235314SRichard Henderson 1155f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY 1156f5235314SRichard Henderson switch (imm) { 1157f5235314SRichard Henderson case 0x8: /* syscall trap */ 1158f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_SYSCALL); 1159f5235314SRichard Henderson break; 1160f5235314SRichard Henderson case 0x18: /* debug trap */ 1161f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1162f5235314SRichard Henderson break; 1163f5235314SRichard Henderson default: /* eliminated with trap_userspace check */ 1164f5235314SRichard Henderson g_assert_not_reached(); 1165f5235314SRichard Henderson } 1166f5235314SRichard Henderson #else 1167f5235314SRichard Henderson uint32_t msr_to_set = 0; 1168f5235314SRichard Henderson 1169f5235314SRichard Henderson if (imm != 0x18) { 1170f5235314SRichard Henderson msr_to_set |= MSR_BIP; 1171f5235314SRichard Henderson } 1172f5235314SRichard Henderson if (imm == 0x8 || imm == 0x18) { 1173f5235314SRichard Henderson /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */ 1174f5235314SRichard Henderson msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1; 1175f5235314SRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, 1176f5235314SRichard Henderson ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM)); 1177f5235314SRichard Henderson } 1178f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set); 1179f5235314SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1180f5235314SRichard Henderson #endif 1181f5235314SRichard Henderson 1182f5235314SRichard Henderson return true; 1183f5235314SRichard Henderson } 1184f5235314SRichard Henderson 1185ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg) 1186ee8c7f9fSRichard Henderson { 1187ee8c7f9fSRichard Henderson int mbar_imm = arg->imm; 1188ee8c7f9fSRichard Henderson 1189ee8c7f9fSRichard Henderson /* Data access memory barrier. */ 1190ee8c7f9fSRichard Henderson if ((mbar_imm & 2) == 0) { 1191ee8c7f9fSRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 1192ee8c7f9fSRichard Henderson } 1193ee8c7f9fSRichard Henderson 1194ee8c7f9fSRichard Henderson /* Sleep. */ 1195ee8c7f9fSRichard Henderson if (mbar_imm & 16) { 1196ee8c7f9fSRichard Henderson TCGv_i32 tmp_1; 1197ee8c7f9fSRichard Henderson 1198ee8c7f9fSRichard Henderson if (trap_userspace(dc, true)) { 1199ee8c7f9fSRichard Henderson /* Sleep is a privileged instruction. */ 1200ee8c7f9fSRichard Henderson return true; 1201ee8c7f9fSRichard Henderson } 1202ee8c7f9fSRichard Henderson 1203ee8c7f9fSRichard Henderson t_sync_flags(dc); 1204ee8c7f9fSRichard Henderson 1205ee8c7f9fSRichard Henderson tmp_1 = tcg_const_i32(1); 1206ee8c7f9fSRichard Henderson tcg_gen_st_i32(tmp_1, cpu_env, 1207ee8c7f9fSRichard Henderson -offsetof(MicroBlazeCPU, env) 1208ee8c7f9fSRichard Henderson +offsetof(CPUState, halted)); 1209ee8c7f9fSRichard Henderson tcg_temp_free_i32(tmp_1); 1210ee8c7f9fSRichard Henderson 1211ee8c7f9fSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1212ee8c7f9fSRichard Henderson 1213ee8c7f9fSRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1214ee8c7f9fSRichard Henderson } 1215ee8c7f9fSRichard Henderson 1216ee8c7f9fSRichard Henderson /* 1217ee8c7f9fSRichard Henderson * If !(mbar_imm & 1), this is an instruction access memory barrier 1218ee8c7f9fSRichard Henderson * and we need to end the TB so that we recognize self-modified 1219ee8c7f9fSRichard Henderson * code immediately. 1220ee8c7f9fSRichard Henderson * 1221ee8c7f9fSRichard Henderson * However, there are some data mbars that need the TB break 1222ee8c7f9fSRichard Henderson * (and return to main loop) to recognize interrupts right away. 1223ee8c7f9fSRichard Henderson * E.g. recognizing a change to an interrupt controller register. 1224ee8c7f9fSRichard Henderson * 1225ee8c7f9fSRichard Henderson * Therefore, choose to end the TB always. 1226ee8c7f9fSRichard Henderson */ 1227ee8c7f9fSRichard Henderson dc->cpustate_changed = 1; 1228ee8c7f9fSRichard Henderson return true; 1229ee8c7f9fSRichard Henderson } 1230ee8c7f9fSRichard Henderson 1231e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set) 1232e6cb0354SRichard Henderson { 1233e6cb0354SRichard Henderson if (trap_userspace(dc, to_set)) { 1234e6cb0354SRichard Henderson return true; 1235e6cb0354SRichard Henderson } 1236e6cb0354SRichard Henderson dc->tb_flags_to_set |= to_set; 1237e6cb0354SRichard Henderson setup_dslot(dc, true); 1238e6cb0354SRichard Henderson 1239e6cb0354SRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 1240e6cb0354SRichard Henderson dc->jmp_dest = -1; 1241e6cb0354SRichard Henderson tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm); 1242e6cb0354SRichard Henderson return true; 1243e6cb0354SRichard Henderson } 1244e6cb0354SRichard Henderson 1245e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \ 1246e6cb0354SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \ 1247e6cb0354SRichard Henderson { return do_rts(dc, arg, IFLAG); } 1248e6cb0354SRichard Henderson 1249e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG) 1250e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG) 1251e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG) 1252e6cb0354SRichard Henderson DO_RTS(rtsd, 0) 1253e6cb0354SRichard Henderson 125420800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 125520800179SRichard Henderson { 125620800179SRichard Henderson /* If opcode_0_illegal, trap. */ 125720800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 125820800179SRichard Henderson trap_illegal(dc, true); 125920800179SRichard Henderson return true; 126020800179SRichard Henderson } 126120800179SRichard Henderson /* 126220800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 126320800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 126420800179SRichard Henderson */ 126520800179SRichard Henderson return false; 1266fcf5ef2aSThomas Huth } 1267fcf5ef2aSThomas Huth 12681074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 1269fcf5ef2aSThomas Huth { 12701074c0fbSRichard Henderson TCGv_i32 t; 12711074c0fbSRichard Henderson 12721074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 12731074c0fbSRichard Henderson t = tcg_temp_new_i32(); 12741074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 12751074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 12761074c0fbSRichard Henderson tcg_temp_free_i32(t); 1277fcf5ef2aSThomas Huth } 1278fcf5ef2aSThomas Huth 12799df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 12801074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 1281fcf5ef2aSThomas Huth { 1282fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 12831074c0fbSRichard Henderson 12841074c0fbSRichard Henderson /* Install MSR_C. */ 12851074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 12861074c0fbSRichard Henderson 12871074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 12881074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 1289fcf5ef2aSThomas Huth } 12909df297a2SRichard Henderson #endif 1291fcf5ef2aSThomas Huth 1292536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set) 1293536e340fSRichard Henderson { 1294536e340fSRichard Henderson uint32_t imm = arg->imm; 1295536e340fSRichard Henderson 1296536e340fSRichard Henderson if (trap_userspace(dc, imm != MSR_C)) { 1297536e340fSRichard Henderson return true; 1298536e340fSRichard Henderson } 1299536e340fSRichard Henderson 1300536e340fSRichard Henderson if (arg->rd) { 1301536e340fSRichard Henderson msr_read(dc, cpu_R[arg->rd]); 1302536e340fSRichard Henderson } 1303536e340fSRichard Henderson 1304536e340fSRichard Henderson /* 1305536e340fSRichard Henderson * Handle the carry bit separately. 1306536e340fSRichard Henderson * This is the only bit that userspace can modify. 1307536e340fSRichard Henderson */ 1308536e340fSRichard Henderson if (imm & MSR_C) { 1309536e340fSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, set); 1310536e340fSRichard Henderson } 1311536e340fSRichard Henderson 1312536e340fSRichard Henderson /* 1313536e340fSRichard Henderson * MSR_C and MSR_CC set above. 1314536e340fSRichard Henderson * MSR_PVR is not writable, and is always clear. 1315536e340fSRichard Henderson */ 1316536e340fSRichard Henderson imm &= ~(MSR_C | MSR_CC | MSR_PVR); 1317536e340fSRichard Henderson 1318536e340fSRichard Henderson if (imm != 0) { 1319536e340fSRichard Henderson if (set) { 1320536e340fSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, imm); 1321536e340fSRichard Henderson } else { 1322536e340fSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm); 1323536e340fSRichard Henderson } 1324536e340fSRichard Henderson dc->cpustate_changed = 1; 1325536e340fSRichard Henderson } 1326536e340fSRichard Henderson return true; 1327536e340fSRichard Henderson } 1328536e340fSRichard Henderson 1329536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg) 1330536e340fSRichard Henderson { 1331536e340fSRichard Henderson return do_msrclrset(dc, arg, false); 1332536e340fSRichard Henderson } 1333536e340fSRichard Henderson 1334536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg) 1335536e340fSRichard Henderson { 1336536e340fSRichard Henderson return do_msrclrset(dc, arg, true); 1337536e340fSRichard Henderson } 1338536e340fSRichard Henderson 13399df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg) 1340fcf5ef2aSThomas Huth { 13419df297a2SRichard Henderson if (trap_userspace(dc, true)) { 13429df297a2SRichard Henderson return true; 1343f0f7e7f7SEdgar E. Iglesias } 1344f0f7e7f7SEdgar E. Iglesias 13459df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY 13469df297a2SRichard Henderson g_assert_not_reached(); 13479df297a2SRichard Henderson #else 13489df297a2SRichard Henderson if (arg->e && arg->rs != 0x1003) { 13499df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 13509df297a2SRichard Henderson "Invalid extended mts reg 0x%x\n", arg->rs); 13519df297a2SRichard Henderson return true; 13522023e9a3SEdgar E. Iglesias } 1353fcf5ef2aSThomas Huth 13549df297a2SRichard Henderson TCGv_i32 src = reg_for_read(dc, arg->ra); 13559df297a2SRichard Henderson switch (arg->rs) { 1356aa28e6d4SRichard Henderson case SR_MSR: 13579df297a2SRichard Henderson msr_write(dc, src); 1358fcf5ef2aSThomas Huth break; 13599df297a2SRichard Henderson case SR_FSR: 13609df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr)); 13619df297a2SRichard Henderson break; 13629df297a2SRichard Henderson case 0x800: 13639df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr)); 13649df297a2SRichard Henderson break; 13659df297a2SRichard Henderson case 0x802: 13669df297a2SRichard Henderson tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr)); 13679df297a2SRichard Henderson break; 13689df297a2SRichard Henderson 13699df297a2SRichard Henderson case 0x1000: /* PID */ 13709df297a2SRichard Henderson case 0x1001: /* ZPR */ 13719df297a2SRichard Henderson case 0x1002: /* TLBX */ 13729df297a2SRichard Henderson case 0x1003: /* TLBLO */ 13739df297a2SRichard Henderson case 0x1004: /* TLBHI */ 13749df297a2SRichard Henderson case 0x1005: /* TLBSX */ 13759df297a2SRichard Henderson { 13769df297a2SRichard Henderson TCGv_i32 tmp_ext = tcg_const_i32(arg->e); 13779df297a2SRichard Henderson TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); 13789df297a2SRichard Henderson 13799df297a2SRichard Henderson gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src); 13809df297a2SRichard Henderson tcg_temp_free_i32(tmp_reg); 13819df297a2SRichard Henderson tcg_temp_free_i32(tmp_ext); 13829df297a2SRichard Henderson } 13839df297a2SRichard Henderson break; 13849df297a2SRichard Henderson 13859df297a2SRichard Henderson default: 13869df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs); 13879df297a2SRichard Henderson return true; 13889df297a2SRichard Henderson } 13899df297a2SRichard Henderson dc->cpustate_changed = 1; 13909df297a2SRichard Henderson return true; 13919df297a2SRichard Henderson #endif 13929df297a2SRichard Henderson } 13939df297a2SRichard Henderson 13949df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg) 13959df297a2SRichard Henderson { 13969df297a2SRichard Henderson TCGv_i32 dest = reg_for_write(dc, arg->rd); 13979df297a2SRichard Henderson 13989df297a2SRichard Henderson if (arg->e) { 13999df297a2SRichard Henderson switch (arg->rs) { 1400351527b7SEdgar E. Iglesias case SR_EAR: 1401dbdb77c4SRichard Henderson { 1402dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 14039df297a2SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14049df297a2SRichard Henderson tcg_gen_extrh_i64_i32(dest, t64); 1405dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1406dbdb77c4SRichard Henderson } 14079df297a2SRichard Henderson return true; 14089df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14099df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14109df297a2SRichard Henderson /* Handled below. */ 1411aa28e6d4SRichard Henderson break; 14129df297a2SRichard Henderson #endif 14139df297a2SRichard Henderson case 0x2006 ... 0x2009: 14149df297a2SRichard Henderson /* High bits of PVR6-9 not implemented. */ 14159df297a2SRichard Henderson tcg_gen_movi_i32(dest, 0); 14169df297a2SRichard Henderson return true; 1417fcf5ef2aSThomas Huth default: 14189df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, 14199df297a2SRichard Henderson "Invalid extended mfs reg 0x%x\n", arg->rs); 14209df297a2SRichard Henderson return true; 1421fcf5ef2aSThomas Huth } 14229df297a2SRichard Henderson } 14239df297a2SRichard Henderson 14249df297a2SRichard Henderson switch (arg->rs) { 1425aa28e6d4SRichard Henderson case SR_PC: 14269df297a2SRichard Henderson tcg_gen_movi_i32(dest, dc->base.pc_next); 1427fcf5ef2aSThomas Huth break; 1428aa28e6d4SRichard Henderson case SR_MSR: 14299df297a2SRichard Henderson msr_read(dc, dest); 1430fcf5ef2aSThomas Huth break; 1431351527b7SEdgar E. Iglesias case SR_EAR: 1432dbdb77c4SRichard Henderson { 1433dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1434dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 14359df297a2SRichard Henderson tcg_gen_extrl_i64_i32(dest, t64); 1436dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1437a1b48e3aSEdgar E. Iglesias } 1438aa28e6d4SRichard Henderson break; 1439351527b7SEdgar E. Iglesias case SR_ESR: 14409df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr)); 1441aa28e6d4SRichard Henderson break; 1442351527b7SEdgar E. Iglesias case SR_FSR: 14439df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr)); 1444aa28e6d4SRichard Henderson break; 1445351527b7SEdgar E. Iglesias case SR_BTR: 14469df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr)); 1447aa28e6d4SRichard Henderson break; 14487cdae31dSTong Ho case SR_EDR: 14499df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr)); 1450fcf5ef2aSThomas Huth break; 1451fcf5ef2aSThomas Huth case 0x800: 14529df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr)); 1453fcf5ef2aSThomas Huth break; 1454fcf5ef2aSThomas Huth case 0x802: 14559df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr)); 1456fcf5ef2aSThomas Huth break; 14579df297a2SRichard Henderson 14589df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY 14599df297a2SRichard Henderson case 0x1000: /* PID */ 14609df297a2SRichard Henderson case 0x1001: /* ZPR */ 14619df297a2SRichard Henderson case 0x1002: /* TLBX */ 14629df297a2SRichard Henderson case 0x1003: /* TLBLO */ 14639df297a2SRichard Henderson case 0x1004: /* TLBHI */ 14649df297a2SRichard Henderson case 0x1005: /* TLBSX */ 14659df297a2SRichard Henderson { 14669df297a2SRichard Henderson TCGv_i32 tmp_ext = tcg_const_i32(arg->e); 14679df297a2SRichard Henderson TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7); 14689df297a2SRichard Henderson 14699df297a2SRichard Henderson gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg); 14709df297a2SRichard Henderson tcg_temp_free_i32(tmp_reg); 14719df297a2SRichard Henderson tcg_temp_free_i32(tmp_ext); 14729df297a2SRichard Henderson } 14739df297a2SRichard Henderson break; 14749df297a2SRichard Henderson #endif 14759df297a2SRichard Henderson 1476351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 14779df297a2SRichard Henderson tcg_gen_ld_i32(dest, cpu_env, 14789df297a2SRichard Henderson offsetof(CPUMBState, pvr.regs[arg->rs - 0x2000])); 1479fcf5ef2aSThomas Huth break; 1480fcf5ef2aSThomas Huth default: 14819df297a2SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs); 1482fcf5ef2aSThomas Huth break; 1483fcf5ef2aSThomas Huth } 14849df297a2SRichard Henderson return true; 1485fcf5ef2aSThomas Huth } 1486fcf5ef2aSThomas Huth 14873fb394fdSRichard Henderson static void do_rti(DisasContext *dc) 1488fcf5ef2aSThomas Huth { 14893fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1490fcf5ef2aSThomas Huth 14913fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 14923fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE); 14933fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM); 14943fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM)); 14953fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 14963fb394fdSRichard Henderson 14973fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1498fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1499fcf5ef2aSThomas Huth } 1500fcf5ef2aSThomas Huth 15013fb394fdSRichard Henderson static void do_rtb(DisasContext *dc) 1502fcf5ef2aSThomas Huth { 15033fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1504fcf5ef2aSThomas Huth 15053fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15063fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP)); 15073fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15083fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 15093fb394fdSRichard Henderson 15103fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1511fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1512fcf5ef2aSThomas Huth } 1513fcf5ef2aSThomas Huth 15143fb394fdSRichard Henderson static void do_rte(DisasContext *dc) 1515fcf5ef2aSThomas Huth { 15163fb394fdSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1517fcf5ef2aSThomas Huth 15183fb394fdSRichard Henderson tcg_gen_shri_i32(tmp, cpu_msr, 1); 15193fb394fdSRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE); 15203fb394fdSRichard Henderson tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM)); 15213fb394fdSRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP)); 15223fb394fdSRichard Henderson tcg_gen_or_i32(cpu_msr, cpu_msr, tmp); 1523fcf5ef2aSThomas Huth 15243fb394fdSRichard Henderson tcg_temp_free_i32(tmp); 1525fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1526fcf5ef2aSThomas Huth } 1527fcf5ef2aSThomas Huth 1528fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 152952065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl) 1530fcf5ef2aSThomas Huth { 1531fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1532fcf5ef2aSThomas Huth 1533bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 153452065d8fSRichard Henderson return true; 1535fcf5ef2aSThomas Huth } 1536fcf5ef2aSThomas Huth 1537cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 153852065d8fSRichard Henderson if (rb) { 153952065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 1540fcf5ef2aSThomas Huth } else { 154152065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 1542fcf5ef2aSThomas Huth } 1543fcf5ef2aSThomas Huth 1544cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 154552065d8fSRichard Henderson gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl); 1546cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1547cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 154852065d8fSRichard Henderson return true; 154952065d8fSRichard Henderson } 155052065d8fSRichard Henderson 155152065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg) 155252065d8fSRichard Henderson { 155352065d8fSRichard Henderson return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl); 155452065d8fSRichard Henderson } 155552065d8fSRichard Henderson 155652065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg) 155752065d8fSRichard Henderson { 155852065d8fSRichard Henderson return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl); 155952065d8fSRichard Henderson } 156052065d8fSRichard Henderson 156152065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl) 156252065d8fSRichard Henderson { 156352065d8fSRichard Henderson TCGv_i32 t_id, t_ctrl; 156452065d8fSRichard Henderson 156552065d8fSRichard Henderson if (trap_userspace(dc, true)) { 156652065d8fSRichard Henderson return true; 156752065d8fSRichard Henderson } 156852065d8fSRichard Henderson 156952065d8fSRichard Henderson t_id = tcg_temp_new_i32(); 157052065d8fSRichard Henderson if (rb) { 157152065d8fSRichard Henderson tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf); 157252065d8fSRichard Henderson } else { 157352065d8fSRichard Henderson tcg_gen_movi_i32(t_id, imm); 157452065d8fSRichard Henderson } 157552065d8fSRichard Henderson 157652065d8fSRichard Henderson t_ctrl = tcg_const_i32(ctrl); 157752065d8fSRichard Henderson gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra)); 157852065d8fSRichard Henderson tcg_temp_free_i32(t_id); 157952065d8fSRichard Henderson tcg_temp_free_i32(t_ctrl); 158052065d8fSRichard Henderson return true; 158152065d8fSRichard Henderson } 158252065d8fSRichard Henderson 158352065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg) 158452065d8fSRichard Henderson { 158552065d8fSRichard Henderson return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl); 158652065d8fSRichard Henderson } 158752065d8fSRichard Henderson 158852065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg) 158952065d8fSRichard Henderson { 159052065d8fSRichard Henderson return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl); 1591fcf5ef2aSThomas Huth } 1592fcf5ef2aSThomas Huth 1593372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1594fcf5ef2aSThomas Huth { 1595372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1596372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1597372122e3SRichard Henderson int bound; 1598fcf5ef2aSThomas Huth 1599fcf5ef2aSThomas Huth dc->cpu = cpu; 1600683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags; 1601fcf5ef2aSThomas Huth dc->cpustate_changed = 0; 1602d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 160320800179SRichard Henderson dc->r0 = NULL; 160420800179SRichard Henderson dc->r0_set = false; 1605287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 1606b9c58aabSRichard Henderson dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; 1607b9c58aabSRichard Henderson dc->jmp_dest = -1; 1608fcf5ef2aSThomas Huth 1609372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1610372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1611fcf5ef2aSThomas Huth } 1612fcf5ef2aSThomas Huth 1613372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1614fcf5ef2aSThomas Huth { 1615fcf5ef2aSThomas Huth } 1616fcf5ef2aSThomas Huth 1617372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1618372122e3SRichard Henderson { 1619683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1620683a247eSRichard Henderson 1621683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); 1622683a247eSRichard Henderson dc->insn_start = tcg_last_op(); 1623372122e3SRichard Henderson } 1624fcf5ef2aSThomas Huth 1625372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1626372122e3SRichard Henderson const CPUBreakpoint *bp) 1627372122e3SRichard Henderson { 1628372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1629372122e3SRichard Henderson 1630372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1631372122e3SRichard Henderson 1632372122e3SRichard Henderson /* 1633372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1634372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1635372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1636372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1637372122e3SRichard Henderson */ 1638372122e3SRichard Henderson dc->base.pc_next += 4; 1639372122e3SRichard Henderson return true; 1640372122e3SRichard Henderson } 1641372122e3SRichard Henderson 1642372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1643372122e3SRichard Henderson { 1644372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1645372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 164644d1432bSRichard Henderson uint32_t ir; 1647372122e3SRichard Henderson 1648372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1649372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1650372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1651372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1652fcf5ef2aSThomas Huth } 1653fcf5ef2aSThomas Huth 16546f9642d7SRichard Henderson dc->tb_flags_to_set = 0; 16556f9642d7SRichard Henderson 165644d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 165744d1432bSRichard Henderson if (!decode(dc, ir)) { 1658*921afa9dSRichard Henderson trap_illegal(dc, true); 165944d1432bSRichard Henderson } 166020800179SRichard Henderson 166120800179SRichard Henderson if (dc->r0) { 166220800179SRichard Henderson tcg_temp_free_i32(dc->r0); 166320800179SRichard Henderson dc->r0 = NULL; 166420800179SRichard Henderson dc->r0_set = false; 166520800179SRichard Henderson } 166620800179SRichard Henderson 16676f9642d7SRichard Henderson /* Discard the imm global when its contents cannot be used. */ 16686f9642d7SRichard Henderson if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { 1669d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1670372122e3SRichard Henderson } 16716f9642d7SRichard Henderson 16721e521ce3SRichard Henderson dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG); 16736f9642d7SRichard Henderson dc->tb_flags |= dc->tb_flags_to_set; 1674d4705ae0SRichard Henderson dc->base.pc_next += 4; 1675fcf5ef2aSThomas Huth 1676b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { 1677372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 1678fcf5ef2aSThomas Huth do_rti(dc); 1679b9c58aabSRichard Henderson } else if (dc->tb_flags & DRTB_FLAG) { 1680fcf5ef2aSThomas Huth do_rtb(dc); 1681b9c58aabSRichard Henderson } else if (dc->tb_flags & DRTE_FLAG) { 1682fcf5ef2aSThomas Huth do_rte(dc); 1683372122e3SRichard Henderson } 1684372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1685372122e3SRichard Henderson } 1686372122e3SRichard Henderson 1687372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1688372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1689372122e3SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1690372122e3SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1691372122e3SRichard Henderson } 1692372122e3SRichard Henderson } 1693372122e3SRichard Henderson 1694372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1695372122e3SRichard Henderson { 1696372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1697372122e3SRichard Henderson 1698372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1699372122e3SRichard Henderson /* We have already exited the TB. */ 1700372122e3SRichard Henderson return; 1701372122e3SRichard Henderson } 1702372122e3SRichard Henderson 1703372122e3SRichard Henderson t_sync_flags(dc); 1704372122e3SRichard Henderson 1705372122e3SRichard Henderson switch (dc->base.is_jmp) { 1706372122e3SRichard Henderson case DISAS_TOO_MANY: 1707372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1708372122e3SRichard Henderson return; 1709372122e3SRichard Henderson 1710372122e3SRichard Henderson case DISAS_UPDATE: 1711372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1712372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1713372122e3SRichard Henderson } else { 1714372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1715372122e3SRichard Henderson } 1716372122e3SRichard Henderson return; 1717372122e3SRichard Henderson 1718372122e3SRichard Henderson case DISAS_JUMP: 1719b9c58aabSRichard Henderson if (dc->jmp_dest != -1 && !cs->singlestep_enabled) { 1720b9c58aabSRichard Henderson /* Direct jump. */ 1721b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1722b9c58aabSRichard Henderson 1723b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_ALWAYS) { 1724b9c58aabSRichard Henderson /* Conditional direct jump. */ 1725b9c58aabSRichard Henderson TCGLabel *taken = gen_new_label(); 1726b9c58aabSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1727b9c58aabSRichard Henderson 1728b9c58aabSRichard Henderson /* 1729b9c58aabSRichard Henderson * Copy bvalue to a temp now, so we can discard bvalue. 1730b9c58aabSRichard Henderson * This can avoid writing bvalue to memory when the 1731b9c58aabSRichard Henderson * delay slot cannot raise an exception. 1732b9c58aabSRichard Henderson */ 1733b9c58aabSRichard Henderson tcg_gen_mov_i32(tmp, cpu_bvalue); 1734b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_bvalue); 1735b9c58aabSRichard Henderson 1736b9c58aabSRichard Henderson tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken); 1737b9c58aabSRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1738b9c58aabSRichard Henderson gen_set_label(taken); 1739b9c58aabSRichard Henderson } 1740b9c58aabSRichard Henderson gen_goto_tb(dc, 0, dc->jmp_dest); 1741b9c58aabSRichard Henderson return; 1742b9c58aabSRichard Henderson } 1743b9c58aabSRichard Henderson 1744b9c58aabSRichard Henderson /* Indirect jump (or direct jump w/ singlestep) */ 1745b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1746b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1747372122e3SRichard Henderson 1748372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1749372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1750372122e3SRichard Henderson } else { 1751372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1752372122e3SRichard Henderson } 1753372122e3SRichard Henderson return; 1754372122e3SRichard Henderson 1755a2b80dbdSRichard Henderson default: 1756a2b80dbdSRichard Henderson g_assert_not_reached(); 1757fcf5ef2aSThomas Huth } 1758fcf5ef2aSThomas Huth } 1759fcf5ef2aSThomas Huth 1760372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1761372122e3SRichard Henderson { 1762372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1763372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 1764fcf5ef2aSThomas Huth } 1765372122e3SRichard Henderson 1766372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1767372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1768372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1769372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1770372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1771372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1772372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1773372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1774372122e3SRichard Henderson }; 1775372122e3SRichard Henderson 1776372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1777372122e3SRichard Henderson { 1778372122e3SRichard Henderson DisasContext dc; 1779372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 1780fcf5ef2aSThomas Huth } 1781fcf5ef2aSThomas Huth 178290c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1783fcf5ef2aSThomas Huth { 1784fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1785fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 17860c3da918SRichard Henderson uint32_t iflags; 1787fcf5ef2aSThomas Huth int i; 1788fcf5ef2aSThomas Huth 17890c3da918SRichard Henderson qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n", 17900c3da918SRichard Henderson env->pc, env->msr, 17912e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 17922e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 17932e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 17942e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 17950c3da918SRichard Henderson 17960c3da918SRichard Henderson iflags = env->iflags; 17970c3da918SRichard Henderson qemu_fprintf(f, "iflags: 0x%08x", iflags); 17980c3da918SRichard Henderson if (iflags & IMM_FLAG) { 17990c3da918SRichard Henderson qemu_fprintf(f, " IMM(0x%08x)", env->imm); 18002ead1b18SJoe Komlodi } 18010c3da918SRichard Henderson if (iflags & BIMM_FLAG) { 18020c3da918SRichard Henderson qemu_fprintf(f, " BIMM"); 18030c3da918SRichard Henderson } 18040c3da918SRichard Henderson if (iflags & D_FLAG) { 1805b9c58aabSRichard Henderson qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget); 18060c3da918SRichard Henderson } 18070c3da918SRichard Henderson if (iflags & DRTI_FLAG) { 18080c3da918SRichard Henderson qemu_fprintf(f, " DRTI"); 18090c3da918SRichard Henderson } 18100c3da918SRichard Henderson if (iflags & DRTE_FLAG) { 18110c3da918SRichard Henderson qemu_fprintf(f, " DRTE"); 18120c3da918SRichard Henderson } 18130c3da918SRichard Henderson if (iflags & DRTB_FLAG) { 18140c3da918SRichard Henderson qemu_fprintf(f, " DRTB"); 18150c3da918SRichard Henderson } 18160c3da918SRichard Henderson if (iflags & ESR_ESS_FLAG) { 18170c3da918SRichard Henderson qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK); 18182ead1b18SJoe Komlodi } 1819fcf5ef2aSThomas Huth 18200c3da918SRichard Henderson qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" 18210c3da918SRichard Henderson "ear=0x%016" PRIx64 " slr=0x%x shr=0x%x\n", 18220c3da918SRichard Henderson env->esr, env->fsr, env->btr, env->edr, 18230c3da918SRichard Henderson env->ear, env->slr, env->shr); 18240c3da918SRichard Henderson 18250c3da918SRichard Henderson for (i = 0; i < 12; i++) { 18260c3da918SRichard Henderson qemu_fprintf(f, "rpvr%-2d=%08x%c", 18270c3da918SRichard Henderson i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' '); 1828fcf5ef2aSThomas Huth } 18290c3da918SRichard Henderson 18300c3da918SRichard Henderson for (i = 0; i < 32; i++) { 18310c3da918SRichard Henderson qemu_fprintf(f, "r%2.2d=%08x%c", 18320c3da918SRichard Henderson i, env->regs[i], i % 4 == 3 ? '\n' : ' '); 18330c3da918SRichard Henderson } 18340c3da918SRichard Henderson qemu_fprintf(f, "\n"); 1835fcf5ef2aSThomas Huth } 1836fcf5ef2aSThomas Huth 1837fcf5ef2aSThomas Huth void mb_tcg_init(void) 1838fcf5ef2aSThomas Huth { 1839480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1840480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1841fcf5ef2aSThomas Huth 1842480d29a8SRichard Henderson static const struct { 1843480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1844480d29a8SRichard Henderson } i32s[] = { 1845480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1846480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1847480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1848480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1849480d29a8SRichard Henderson 1850480d29a8SRichard Henderson SP(pc), 1851480d29a8SRichard Henderson SP(msr), 18521074c0fbSRichard Henderson SP(msr_c), 1853480d29a8SRichard Henderson SP(imm), 1854480d29a8SRichard Henderson SP(iflags), 1855b9c58aabSRichard Henderson SP(bvalue), 1856480d29a8SRichard Henderson SP(btarget), 1857480d29a8SRichard Henderson SP(res_val), 1858480d29a8SRichard Henderson }; 1859480d29a8SRichard Henderson 1860480d29a8SRichard Henderson #undef R 1861480d29a8SRichard Henderson #undef SP 1862480d29a8SRichard Henderson 1863480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1864480d29a8SRichard Henderson *i32s[i].var = 1865480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1866fcf5ef2aSThomas Huth } 186776e8187dSRichard Henderson 1868480d29a8SRichard Henderson cpu_res_addr = 1869480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1870fcf5ef2aSThomas Huth } 1871fcf5ef2aSThomas Huth 1872fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1873fcf5ef2aSThomas Huth target_ulong *data) 1874fcf5ef2aSThomas Huth { 187576e8187dSRichard Henderson env->pc = data[0]; 1876683a247eSRichard Henderson env->iflags = data[1]; 1877fcf5ef2aSThomas Huth } 1878