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 "microblaze-decode.h" 28fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h" 29fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 3077fc6f5eSLluís Vilanova #include "exec/translator.h" 3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 32fcf5ef2aSThomas Huth 33fcf5ef2aSThomas Huth #include "trace-tcg.h" 34fcf5ef2aSThomas Huth #include "exec/log.h" 35fcf5ef2aSThomas Huth 36fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 37fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 38fcf5ef2aSThomas Huth 3977fc6f5eSLluís Vilanova /* is_jmp field values */ 4077fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 4177fc6f5eSLluís Vilanova #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ 4277fc6f5eSLluís Vilanova 43cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 440f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 453e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 461074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 479b158558SRichard Henderson static TCGv_i32 cpu_imm; 48*b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue; 490f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 509b158558SRichard Henderson static TCGv_i32 cpu_iflags; 519b158558SRichard Henderson static TCGv cpu_res_addr; 529b158558SRichard Henderson static TCGv_i32 cpu_res_val; 53fcf5ef2aSThomas Huth 54fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 55fcf5ef2aSThomas Huth 56fcf5ef2aSThomas Huth /* This is the state at translation time. */ 57fcf5ef2aSThomas Huth typedef struct DisasContext { 58d4705ae0SRichard Henderson DisasContextBase base; 59fcf5ef2aSThomas Huth MicroBlazeCPU *cpu; 60fcf5ef2aSThomas Huth 61683a247eSRichard Henderson /* TCG op of the current insn_start. */ 62683a247eSRichard Henderson TCGOp *insn_start; 63683a247eSRichard Henderson 6420800179SRichard Henderson TCGv_i32 r0; 6520800179SRichard Henderson bool r0_set; 6620800179SRichard Henderson 67fcf5ef2aSThomas Huth /* Decoder. */ 68fcf5ef2aSThomas Huth int type_b; 69fcf5ef2aSThomas Huth uint32_t ir; 70d7ecb757SRichard Henderson uint32_t ext_imm; 71fcf5ef2aSThomas Huth uint8_t opcode; 72fcf5ef2aSThomas Huth uint8_t rd, ra, rb; 73fcf5ef2aSThomas Huth uint16_t imm; 74fcf5ef2aSThomas Huth 75fcf5ef2aSThomas Huth unsigned int cpustate_changed; 76683a247eSRichard Henderson unsigned int tb_flags; 776f9642d7SRichard Henderson unsigned int tb_flags_to_set; 78287b1defSRichard Henderson int mem_index; 79fcf5ef2aSThomas Huth 80*b9c58aabSRichard Henderson /* Condition under which to jump, including NEVER and ALWAYS. */ 81*b9c58aabSRichard Henderson TCGCond jmp_cond; 82*b9c58aabSRichard Henderson 83*b9c58aabSRichard Henderson /* Immediate branch-taken destination, or -1 for indirect. */ 84*b9c58aabSRichard Henderson uint32_t jmp_dest; 85fcf5ef2aSThomas Huth 86fcf5ef2aSThomas Huth int abort_at_next_insn; 87fcf5ef2aSThomas Huth } DisasContext; 88fcf5ef2aSThomas Huth 8920800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 9020800179SRichard Henderson { 9120800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 9220800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 9320800179SRichard Henderson } 9420800179SRichard Henderson return x; 9520800179SRichard Henderson } 9620800179SRichard Henderson 9744d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9844d1432bSRichard Henderson #include "decode-insns.c.inc" 9944d1432bSRichard Henderson 100683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc) 101fcf5ef2aSThomas Huth { 102fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 103683a247eSRichard Henderson if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) { 104683a247eSRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK); 105fcf5ef2aSThomas Huth } 106fcf5ef2aSThomas Huth } 107fcf5ef2aSThomas Huth 10841ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 109fcf5ef2aSThomas Huth { 110fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 111fcf5ef2aSThomas Huth 112fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 113fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 114d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 115fcf5ef2aSThomas Huth } 116fcf5ef2aSThomas Huth 11741ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11841ba37c4SRichard Henderson { 11941ba37c4SRichard Henderson t_sync_flags(dc); 120d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 12141ba37c4SRichard Henderson gen_raise_exception(dc, index); 12241ba37c4SRichard Henderson } 12341ba37c4SRichard Henderson 12441ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12541ba37c4SRichard Henderson { 12641ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12741ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12841ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12941ba37c4SRichard Henderson 13041ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 13141ba37c4SRichard Henderson } 13241ba37c4SRichard Henderson 133fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 134fcf5ef2aSThomas Huth { 135fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 136d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 137fcf5ef2aSThomas Huth #else 138fcf5ef2aSThomas Huth return true; 139fcf5ef2aSThomas Huth #endif 140fcf5ef2aSThomas Huth } 141fcf5ef2aSThomas Huth 142fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 143fcf5ef2aSThomas Huth { 144d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1450b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1460b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1470b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1480b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1490b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 150fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1510f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 152d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 153fcf5ef2aSThomas Huth } else { 1540f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 15507ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 156fcf5ef2aSThomas Huth } 157d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 158fcf5ef2aSThomas Huth } 159fcf5ef2aSThomas Huth 160bdfc1e88SEdgar E. Iglesias /* 1619ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1629ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1639ba8cd45SEdgar E. Iglesias */ 1649ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1659ba8cd45SEdgar E. Iglesias { 1662c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE) 1675143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 16841ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1699ba8cd45SEdgar E. Iglesias } 1709ba8cd45SEdgar E. Iglesias return cond; 1719ba8cd45SEdgar E. Iglesias } 1729ba8cd45SEdgar E. Iglesias 1739ba8cd45SEdgar E. Iglesias /* 174bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 175bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 176bdfc1e88SEdgar E. Iglesias */ 177bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 178bdfc1e88SEdgar E. Iglesias { 179287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX; 180bdfc1e88SEdgar E. Iglesias 1812c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) { 18241ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 183bdfc1e88SEdgar E. Iglesias } 184bdfc1e88SEdgar E. Iglesias return cond_user; 185bdfc1e88SEdgar E. Iglesias } 186bdfc1e88SEdgar E. Iglesias 187d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc) 188fcf5ef2aSThomas Huth { 189d7ecb757SRichard Henderson tcg_debug_assert(dc->type_b); 19020800179SRichard Henderson return typeb_imm(dc, (int16_t)dc->imm); 191fcf5ef2aSThomas Huth } 192fcf5ef2aSThomas Huth 193cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) 194fcf5ef2aSThomas Huth { 195fcf5ef2aSThomas Huth if (dc->type_b) { 196d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc)); 1979b158558SRichard Henderson return &cpu_imm; 198d7ecb757SRichard Henderson } 199fcf5ef2aSThomas Huth return &cpu_R[dc->rb]; 200fcf5ef2aSThomas Huth } 201fcf5ef2aSThomas Huth 20220800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 203fcf5ef2aSThomas Huth { 20420800179SRichard Henderson if (likely(reg != 0)) { 20520800179SRichard Henderson return cpu_R[reg]; 206fcf5ef2aSThomas Huth } 20720800179SRichard Henderson if (!dc->r0_set) { 20820800179SRichard Henderson if (dc->r0 == NULL) { 20920800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 210fcf5ef2aSThomas Huth } 21120800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 21220800179SRichard Henderson dc->r0_set = true; 21320800179SRichard Henderson } 21420800179SRichard Henderson return dc->r0; 215fcf5ef2aSThomas Huth } 216fcf5ef2aSThomas Huth 21720800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 21820800179SRichard Henderson { 21920800179SRichard Henderson if (likely(reg != 0)) { 22020800179SRichard Henderson return cpu_R[reg]; 22120800179SRichard Henderson } 22220800179SRichard Henderson if (dc->r0 == NULL) { 22320800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 22420800179SRichard Henderson } 22520800179SRichard Henderson return dc->r0; 226fcf5ef2aSThomas Huth } 227fcf5ef2aSThomas Huth 22820800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 22920800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 23020800179SRichard Henderson { 23120800179SRichard Henderson TCGv_i32 rd, ra, rb; 23220800179SRichard Henderson 23320800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 23420800179SRichard Henderson return true; 235fcf5ef2aSThomas Huth } 23620800179SRichard Henderson 23720800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 23820800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 23920800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 24020800179SRichard Henderson fn(rd, ra, rb); 24120800179SRichard Henderson return true; 24220800179SRichard Henderson } 24320800179SRichard Henderson 24439cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, 24539cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32)) 24639cf3864SRichard Henderson { 24739cf3864SRichard Henderson TCGv_i32 rd, ra; 24839cf3864SRichard Henderson 24939cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) { 25039cf3864SRichard Henderson return true; 25139cf3864SRichard Henderson } 25239cf3864SRichard Henderson 25339cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd); 25439cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra); 25539cf3864SRichard Henderson fn(rd, ra); 25639cf3864SRichard Henderson return true; 25739cf3864SRichard Henderson } 25839cf3864SRichard Henderson 25920800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 26020800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 26120800179SRichard Henderson { 26220800179SRichard Henderson TCGv_i32 rd, ra; 26320800179SRichard Henderson 26420800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 26520800179SRichard Henderson return true; 26620800179SRichard Henderson } 26720800179SRichard Henderson 26820800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 26920800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 27020800179SRichard Henderson fni(rd, ra, arg->imm); 27120800179SRichard Henderson return true; 27220800179SRichard Henderson } 27320800179SRichard Henderson 27420800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 27520800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 27620800179SRichard Henderson { 27720800179SRichard Henderson TCGv_i32 rd, ra, imm; 27820800179SRichard Henderson 27920800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 28020800179SRichard Henderson return true; 28120800179SRichard Henderson } 28220800179SRichard Henderson 28320800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 28420800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 28520800179SRichard Henderson imm = tcg_const_i32(arg->imm); 28620800179SRichard Henderson 28720800179SRichard Henderson fn(rd, ra, imm); 28820800179SRichard Henderson 28920800179SRichard Henderson tcg_temp_free_i32(imm); 29020800179SRichard Henderson return true; 29120800179SRichard Henderson } 29220800179SRichard Henderson 29320800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 29420800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 29520800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 29620800179SRichard Henderson 297607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 298607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 299607f5767SRichard Henderson { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } 300607f5767SRichard Henderson 30139cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 30239cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 30339cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 30439cf3864SRichard Henderson 30539cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 30639cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 30739cf3864SRichard Henderson { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); } 30839cf3864SRichard Henderson 30920800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 31020800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 31120800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 31220800179SRichard Henderson 31397955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 31497955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 31597955cebSRichard Henderson { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } 31697955cebSRichard Henderson 31720800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 31820800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 31920800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 32020800179SRichard Henderson 321d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 322d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 323d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 324d5aead3dSRichard Henderson 325d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 326d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 327d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 328d5aead3dSRichard Henderson 32920800179SRichard Henderson /* No input carry, but output carry. */ 33020800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 33120800179SRichard Henderson { 33220800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 33320800179SRichard Henderson 33420800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 33520800179SRichard Henderson 33620800179SRichard Henderson tcg_temp_free_i32(zero); 33720800179SRichard Henderson } 33820800179SRichard Henderson 33920800179SRichard Henderson /* Input and output carry. */ 34020800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 34120800179SRichard Henderson { 34220800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 34320800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 34420800179SRichard Henderson 34520800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 34620800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 34720800179SRichard Henderson 34820800179SRichard Henderson tcg_temp_free_i32(tmp); 34920800179SRichard Henderson tcg_temp_free_i32(zero); 35020800179SRichard Henderson } 35120800179SRichard Henderson 35220800179SRichard Henderson /* Input carry, but no output carry. */ 35320800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 35420800179SRichard Henderson { 35520800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 35620800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 35720800179SRichard Henderson } 35820800179SRichard Henderson 35920800179SRichard Henderson DO_TYPEA(add, true, gen_add) 36020800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 36120800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 36220800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 36320800179SRichard Henderson 36420800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 36520800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 36620800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 36720800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 36820800179SRichard Henderson 369cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 370cb0a0a4cSRichard Henderson { 371cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 372cb0a0a4cSRichard Henderson } 373cb0a0a4cSRichard Henderson 374cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 375cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 376cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 377cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 378cb0a0a4cSRichard Henderson 379081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 380081d8e02SRichard Henderson { 381081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 382081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 383081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 384081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 385081d8e02SRichard Henderson } 386081d8e02SRichard Henderson 387081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 388081d8e02SRichard Henderson { 389081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 390081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 391081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 392081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 393081d8e02SRichard Henderson } 394081d8e02SRichard Henderson 395081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 396081d8e02SRichard Henderson { 397081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 398081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 399081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 400081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 401081d8e02SRichard Henderson } 402081d8e02SRichard Henderson 403081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 404081d8e02SRichard Henderson { 405081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 406081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 407081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 408081d8e02SRichard Henderson 409081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 410081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 411081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 412081d8e02SRichard Henderson imm_w, imm_s); 413081d8e02SRichard Henderson } else { 414081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 415081d8e02SRichard Henderson } 416081d8e02SRichard Henderson } 417081d8e02SRichard Henderson 418081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 419081d8e02SRichard Henderson { 420081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 421081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 422081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 423081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 424081d8e02SRichard Henderson 425081d8e02SRichard Henderson if (imm_w < imm_s) { 426081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 427081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 428081d8e02SRichard Henderson imm_w, imm_s); 429081d8e02SRichard Henderson } else { 430081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 431081d8e02SRichard Henderson } 432081d8e02SRichard Henderson } 433081d8e02SRichard Henderson 434081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 435081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 436081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 437081d8e02SRichard Henderson 438081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 439081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 440081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 441081d8e02SRichard Henderson 442081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 443081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 444081d8e02SRichard Henderson 44539cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 44639cf3864SRichard Henderson { 44739cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 44839cf3864SRichard Henderson } 44939cf3864SRichard Henderson 45039cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 45139cf3864SRichard Henderson 45258b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 45358b48b63SRichard Henderson { 45458b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 45558b48b63SRichard Henderson 45658b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 45758b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 45858b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 45958b48b63SRichard Henderson tcg_temp_free_i32(lt); 46058b48b63SRichard Henderson } 46158b48b63SRichard Henderson 46258b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 46358b48b63SRichard Henderson { 46458b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 46558b48b63SRichard Henderson 46658b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 46758b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 46858b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 46958b48b63SRichard Henderson tcg_temp_free_i32(lt); 47058b48b63SRichard Henderson } 47158b48b63SRichard Henderson 47258b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 47358b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 474a2b0b90eSRichard Henderson 475d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 476d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 477d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 478d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 479d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 480d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 481d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 482d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 483d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 484d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 485d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 486d5aead3dSRichard Henderson 487d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 488d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 489d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 490d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 491d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 492d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 493d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 494d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 495d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 496d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 497d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 498d5aead3dSRichard Henderson 499d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 500d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 501d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 502d5aead3dSRichard Henderson 503d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 504d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 505d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 506d5aead3dSRichard Henderson 507d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 508b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 509b1354342SRichard Henderson { 510b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 511b1354342SRichard Henderson } 512b1354342SRichard Henderson 513b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 514b1354342SRichard Henderson { 515b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 516b1354342SRichard Henderson } 517b1354342SRichard Henderson 518b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 519b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 520b1354342SRichard Henderson 521e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 522e64b2e5cSRichard Henderson { 523e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 524e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 5256f9642d7SRichard Henderson dc->tb_flags_to_set = IMM_FLAG; 526e64b2e5cSRichard Henderson return true; 527e64b2e5cSRichard Henderson } 528e64b2e5cSRichard Henderson 52997955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 53097955cebSRichard Henderson { 53197955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 53297955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 53397955cebSRichard Henderson tcg_temp_free_i32(tmp); 53497955cebSRichard Henderson } 53597955cebSRichard Henderson 53697955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 53797955cebSRichard Henderson { 53897955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 53997955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 54097955cebSRichard Henderson tcg_temp_free_i32(tmp); 54197955cebSRichard Henderson } 54297955cebSRichard Henderson 54397955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 54497955cebSRichard Henderson { 54597955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 54697955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 54797955cebSRichard Henderson tcg_temp_free_i32(tmp); 54897955cebSRichard Henderson } 54997955cebSRichard Henderson 55097955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 55197955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 55297955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 55397955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 55497955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 55597955cebSRichard Henderson 556cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 557cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 558cb0a0a4cSRichard Henderson 559607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 560607f5767SRichard Henderson { 561607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 562607f5767SRichard Henderson } 563607f5767SRichard Henderson 564607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 565607f5767SRichard Henderson { 566607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 567607f5767SRichard Henderson } 568607f5767SRichard Henderson 569607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 570607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 571607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 572607f5767SRichard Henderson 573a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 574a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 575a2b0b90eSRichard Henderson { 576a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 577a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 578a2b0b90eSRichard Henderson } 579a2b0b90eSRichard Henderson 580a2b0b90eSRichard Henderson /* Input and output carry. */ 581a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 582a2b0b90eSRichard Henderson { 583a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 584a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 585a2b0b90eSRichard Henderson 586a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 587a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 588a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 589a2b0b90eSRichard Henderson 590a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 591a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 592a2b0b90eSRichard Henderson } 593a2b0b90eSRichard Henderson 594a2b0b90eSRichard Henderson /* No input or output carry. */ 595a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 596a2b0b90eSRichard Henderson { 597a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 598a2b0b90eSRichard Henderson } 599a2b0b90eSRichard Henderson 600a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 601a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 602a2b0b90eSRichard Henderson { 603a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 604a2b0b90eSRichard Henderson 605a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 606a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 607a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 608a2b0b90eSRichard Henderson 609a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 610a2b0b90eSRichard Henderson } 611a2b0b90eSRichard Henderson 612a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 613a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 614a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 615a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 616a2b0b90eSRichard Henderson 617a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 618a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 619a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 620a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 621a2b0b90eSRichard Henderson 62239cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 62339cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 62439cf3864SRichard Henderson 62539cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 62639cf3864SRichard Henderson { 62739cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 62839cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 62939cf3864SRichard Henderson } 63039cf3864SRichard Henderson 63139cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 63239cf3864SRichard Henderson { 63339cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 63439cf3864SRichard Henderson 63539cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 63639cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 63739cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 63839cf3864SRichard Henderson 63939cf3864SRichard Henderson tcg_temp_free_i32(tmp); 64039cf3864SRichard Henderson } 64139cf3864SRichard Henderson 64239cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 64339cf3864SRichard Henderson { 64439cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 64539cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 64639cf3864SRichard Henderson } 64739cf3864SRichard Henderson 64839cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 64939cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 65039cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 65139cf3864SRichard Henderson 65239cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 65339cf3864SRichard Henderson { 65439cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 65539cf3864SRichard Henderson } 65639cf3864SRichard Henderson 65739cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 65839cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 65939cf3864SRichard Henderson 66039cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 66139cf3864SRichard Henderson { 66239cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 66339cf3864SRichard Henderson trap_userspace(dc, true); 66439cf3864SRichard Henderson return true; 66539cf3864SRichard Henderson } 66639cf3864SRichard Henderson 667cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 668cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 669cb0a0a4cSRichard Henderson 670d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 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 && rb) { 676d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 677d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 678d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 679d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 680d8e59c4aSRichard Henderson } else if (ra) { 681d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 682d8e59c4aSRichard Henderson } else if (rb) { 683d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 684d8e59c4aSRichard Henderson } else { 685d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 686d8e59c4aSRichard Henderson } 687d8e59c4aSRichard Henderson 688d8e59c4aSRichard Henderson if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) { 689d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 690d8e59c4aSRichard Henderson } 691d8e59c4aSRichard Henderson return ret; 692d8e59c4aSRichard Henderson } 693d8e59c4aSRichard Henderson 694d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 695d8e59c4aSRichard Henderson { 696d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 697d8e59c4aSRichard Henderson 698d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 699d8e59c4aSRichard Henderson if (ra) { 700d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 701d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 702d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 703d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 704d8e59c4aSRichard Henderson } else { 705d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 706d8e59c4aSRichard Henderson } 707d8e59c4aSRichard Henderson 708d8e59c4aSRichard Henderson if (ra == 1 && dc->cpu->cfg.stackprot) { 709d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 710d8e59c4aSRichard Henderson } 711d8e59c4aSRichard Henderson return ret; 712d8e59c4aSRichard Henderson } 713d8e59c4aSRichard Henderson 714d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 715d8e59c4aSRichard Henderson { 716d8e59c4aSRichard Henderson int addr_size = dc->cpu->cfg.addr_size; 717d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 718d8e59c4aSRichard Henderson 719d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 720d8e59c4aSRichard Henderson if (rb) { 721d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 722d8e59c4aSRichard Henderson } else { 723d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 724d8e59c4aSRichard Henderson } 725d8e59c4aSRichard Henderson } else { 726d8e59c4aSRichard Henderson if (rb) { 727d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 728d8e59c4aSRichard Henderson } else { 729d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 730d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 731d8e59c4aSRichard Henderson } 732d8e59c4aSRichard Henderson if (addr_size < 64) { 733d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 734d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 735d8e59c4aSRichard Henderson } 736d8e59c4aSRichard Henderson } 737d8e59c4aSRichard Henderson return ret; 738d8e59c4aSRichard Henderson } 739d8e59c4aSRichard Henderson 740ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd, 741ab0c8d0fSRichard Henderson MemOp size, bool store) 742ab0c8d0fSRichard Henderson { 743ab0c8d0fSRichard Henderson uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1); 744ab0c8d0fSRichard Henderson 745ab0c8d0fSRichard Henderson iflags |= ESR_ESS_FLAG; 746ab0c8d0fSRichard Henderson iflags |= rd << 5; 747ab0c8d0fSRichard Henderson iflags |= store * ESR_S; 748ab0c8d0fSRichard Henderson iflags |= (size == MO_32) * ESR_W; 749ab0c8d0fSRichard Henderson 750ab0c8d0fSRichard Henderson tcg_set_insn_start_param(dc->insn_start, 1, iflags); 751ab0c8d0fSRichard Henderson } 752ab0c8d0fSRichard Henderson 753d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 754d8e59c4aSRichard Henderson int mem_index, bool rev) 755d8e59c4aSRichard Henderson { 756d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 757d8e59c4aSRichard Henderson 758d8e59c4aSRichard Henderson /* 759d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 760d8e59c4aSRichard Henderson * 761d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 762d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 763d8e59c4aSRichard Henderson */ 764d8e59c4aSRichard Henderson if (rev) { 765d8e59c4aSRichard Henderson if (size > MO_8) { 766d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 767d8e59c4aSRichard Henderson } 768d8e59c4aSRichard Henderson if (size < MO_32) { 769d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 770d8e59c4aSRichard Henderson } 771d8e59c4aSRichard Henderson } 772d8e59c4aSRichard Henderson 773ab0c8d0fSRichard Henderson if (size > MO_8 && 774ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 775ab0c8d0fSRichard Henderson dc->cpu->cfg.unaligned_exceptions) { 776ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, false); 777ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 778d8e59c4aSRichard Henderson } 779d8e59c4aSRichard Henderson 780ab0c8d0fSRichard Henderson tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop); 781d8e59c4aSRichard Henderson 782d8e59c4aSRichard Henderson tcg_temp_free(addr); 783d8e59c4aSRichard Henderson return true; 784d8e59c4aSRichard Henderson } 785d8e59c4aSRichard Henderson 786d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 787d8e59c4aSRichard Henderson { 788d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 789d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 790d8e59c4aSRichard Henderson } 791d8e59c4aSRichard Henderson 792d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 793d8e59c4aSRichard Henderson { 794d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 795d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 796d8e59c4aSRichard Henderson } 797d8e59c4aSRichard Henderson 798d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 799d8e59c4aSRichard Henderson { 800d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 801d8e59c4aSRichard Henderson return true; 802d8e59c4aSRichard Henderson } 803d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 804d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 805d8e59c4aSRichard Henderson } 806d8e59c4aSRichard Henderson 807d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 808d8e59c4aSRichard Henderson { 809d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 810d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 811d8e59c4aSRichard Henderson } 812d8e59c4aSRichard Henderson 813d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 814d8e59c4aSRichard Henderson { 815d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 816d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 817d8e59c4aSRichard Henderson } 818d8e59c4aSRichard Henderson 819d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 820d8e59c4aSRichard Henderson { 821d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 822d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 823d8e59c4aSRichard Henderson } 824d8e59c4aSRichard Henderson 825d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 826d8e59c4aSRichard Henderson { 827d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 828d8e59c4aSRichard Henderson return true; 829d8e59c4aSRichard Henderson } 830d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 831d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 832d8e59c4aSRichard Henderson } 833d8e59c4aSRichard Henderson 834d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 835d8e59c4aSRichard Henderson { 836d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 837d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 838d8e59c4aSRichard Henderson } 839d8e59c4aSRichard Henderson 840d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 841d8e59c4aSRichard Henderson { 842d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 843d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 844d8e59c4aSRichard Henderson } 845d8e59c4aSRichard Henderson 846d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 847d8e59c4aSRichard Henderson { 848d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 849d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 850d8e59c4aSRichard Henderson } 851d8e59c4aSRichard Henderson 852d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 853d8e59c4aSRichard Henderson { 854d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 855d8e59c4aSRichard Henderson return true; 856d8e59c4aSRichard Henderson } 857d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 858d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 859d8e59c4aSRichard Henderson } 860d8e59c4aSRichard Henderson 861d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg) 862d8e59c4aSRichard Henderson { 863d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 864d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 865d8e59c4aSRichard Henderson } 866d8e59c4aSRichard Henderson 867d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg) 868d8e59c4aSRichard Henderson { 869d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 870d8e59c4aSRichard Henderson 871d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */ 872d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 873d8e59c4aSRichard Henderson 874d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); 875d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 876d8e59c4aSRichard Henderson tcg_temp_free(addr); 877d8e59c4aSRichard Henderson 878d8e59c4aSRichard Henderson if (arg->rd) { 879d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 880d8e59c4aSRichard Henderson } 881d8e59c4aSRichard Henderson 882d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 883d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 884d8e59c4aSRichard Henderson return true; 885d8e59c4aSRichard Henderson } 886d8e59c4aSRichard Henderson 887d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 888d8e59c4aSRichard Henderson int mem_index, bool rev) 889d8e59c4aSRichard Henderson { 890d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 891d8e59c4aSRichard Henderson 892d8e59c4aSRichard Henderson /* 893d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 894d8e59c4aSRichard Henderson * 895d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 896d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 897d8e59c4aSRichard Henderson */ 898d8e59c4aSRichard Henderson if (rev) { 899d8e59c4aSRichard Henderson if (size > MO_8) { 900d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 901d8e59c4aSRichard Henderson } 902d8e59c4aSRichard Henderson if (size < MO_32) { 903d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 904d8e59c4aSRichard Henderson } 905d8e59c4aSRichard Henderson } 906d8e59c4aSRichard Henderson 907ab0c8d0fSRichard Henderson if (size > MO_8 && 908ab0c8d0fSRichard Henderson (dc->tb_flags & MSR_EE) && 909ab0c8d0fSRichard Henderson dc->cpu->cfg.unaligned_exceptions) { 910ab0c8d0fSRichard Henderson record_unaligned_ess(dc, rd, size, true); 911ab0c8d0fSRichard Henderson mop |= MO_ALIGN; 912d8e59c4aSRichard Henderson } 913d8e59c4aSRichard Henderson 914ab0c8d0fSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 915ab0c8d0fSRichard Henderson 916d8e59c4aSRichard Henderson tcg_temp_free(addr); 917d8e59c4aSRichard Henderson return true; 918d8e59c4aSRichard Henderson } 919d8e59c4aSRichard Henderson 920d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 921d8e59c4aSRichard Henderson { 922d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 923d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 924d8e59c4aSRichard Henderson } 925d8e59c4aSRichard Henderson 926d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 927d8e59c4aSRichard Henderson { 928d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 929d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 930d8e59c4aSRichard Henderson } 931d8e59c4aSRichard Henderson 932d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 933d8e59c4aSRichard Henderson { 934d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 935d8e59c4aSRichard Henderson return true; 936d8e59c4aSRichard Henderson } 937d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 938d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 939d8e59c4aSRichard Henderson } 940d8e59c4aSRichard Henderson 941d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 942d8e59c4aSRichard Henderson { 943d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 944d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 945d8e59c4aSRichard Henderson } 946d8e59c4aSRichard Henderson 947d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg) 948d8e59c4aSRichard Henderson { 949d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 950d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 951d8e59c4aSRichard Henderson } 952d8e59c4aSRichard Henderson 953d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 954d8e59c4aSRichard Henderson { 955d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 956d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 957d8e59c4aSRichard Henderson } 958d8e59c4aSRichard Henderson 959d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 960d8e59c4aSRichard Henderson { 961d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 962d8e59c4aSRichard Henderson return true; 963d8e59c4aSRichard Henderson } 964d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 965d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 966d8e59c4aSRichard Henderson } 967d8e59c4aSRichard Henderson 968d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 969d8e59c4aSRichard Henderson { 970d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 971d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 972d8e59c4aSRichard Henderson } 973d8e59c4aSRichard Henderson 974d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 975d8e59c4aSRichard Henderson { 976d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 977d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 978d8e59c4aSRichard Henderson } 979d8e59c4aSRichard Henderson 980d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 981d8e59c4aSRichard Henderson { 982d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 983d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 984d8e59c4aSRichard Henderson } 985d8e59c4aSRichard Henderson 986d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 987d8e59c4aSRichard Henderson { 988d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 989d8e59c4aSRichard Henderson return true; 990d8e59c4aSRichard Henderson } 991d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 992d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 993d8e59c4aSRichard Henderson } 994d8e59c4aSRichard Henderson 995d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 996d8e59c4aSRichard Henderson { 997d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 998d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 999d8e59c4aSRichard Henderson } 1000d8e59c4aSRichard Henderson 1001d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 1002d8e59c4aSRichard Henderson { 1003d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1004d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 1005d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 1006d8e59c4aSRichard Henderson TCGv_i32 tval; 1007d8e59c4aSRichard Henderson 1008d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 1009d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1010d8e59c4aSRichard Henderson 1011d8e59c4aSRichard Henderson /* 1012d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 1013d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 1014d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 1015d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 1016d8e59c4aSRichard Henderson */ 1017d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 1018d8e59c4aSRichard Henderson tcg_temp_free(addr); 1019d8e59c4aSRichard Henderson 1020d8e59c4aSRichard Henderson /* 1021d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 1022d8e59c4aSRichard Henderson * the reserved location. 1023d8e59c4aSRichard Henderson */ 1024d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1025d8e59c4aSRichard Henderson 1026d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1027d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1028d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1029d8e59c4aSRichard Henderson 1030d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1031d8e59c4aSRichard Henderson tcg_temp_free_i32(tval); 1032d8e59c4aSRichard Henderson 1033d8e59c4aSRichard Henderson /* Success */ 1034d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1035d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1036d8e59c4aSRichard Henderson 1037d8e59c4aSRichard Henderson /* Failure */ 1038d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1039d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1040d8e59c4aSRichard Henderson 1041d8e59c4aSRichard Henderson gen_set_label(swx_done); 1042d8e59c4aSRichard Henderson 1043d8e59c4aSRichard Henderson /* 1044d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1045d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1046d8e59c4aSRichard Henderson */ 1047d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1048d8e59c4aSRichard Henderson return true; 1049d8e59c4aSRichard Henderson } 1050d8e59c4aSRichard Henderson 1051f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg) 1052f5235314SRichard Henderson { 1053f5235314SRichard Henderson if (trap_userspace(dc, true)) { 1054f5235314SRichard Henderson return true; 1055f5235314SRichard Henderson } 1056f5235314SRichard Henderson tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb)); 1057f5235314SRichard Henderson if (arg->rd) { 1058f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1059f5235314SRichard Henderson } 1060f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP); 1061f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1062f5235314SRichard Henderson 1063f5235314SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1064f5235314SRichard Henderson return true; 1065f5235314SRichard Henderson } 1066f5235314SRichard Henderson 1067f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg) 1068f5235314SRichard Henderson { 1069f5235314SRichard Henderson uint32_t imm = arg->imm; 1070f5235314SRichard Henderson 1071f5235314SRichard Henderson if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) { 1072f5235314SRichard Henderson return true; 1073f5235314SRichard Henderson } 1074f5235314SRichard Henderson tcg_gen_movi_i32(cpu_pc, imm); 1075f5235314SRichard Henderson if (arg->rd) { 1076f5235314SRichard Henderson tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next); 1077f5235314SRichard Henderson } 1078f5235314SRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1079f5235314SRichard Henderson 1080f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY 1081f5235314SRichard Henderson switch (imm) { 1082f5235314SRichard Henderson case 0x8: /* syscall trap */ 1083f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_SYSCALL); 1084f5235314SRichard Henderson break; 1085f5235314SRichard Henderson case 0x18: /* debug trap */ 1086f5235314SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1087f5235314SRichard Henderson break; 1088f5235314SRichard Henderson default: /* eliminated with trap_userspace check */ 1089f5235314SRichard Henderson g_assert_not_reached(); 1090f5235314SRichard Henderson } 1091f5235314SRichard Henderson #else 1092f5235314SRichard Henderson uint32_t msr_to_set = 0; 1093f5235314SRichard Henderson 1094f5235314SRichard Henderson if (imm != 0x18) { 1095f5235314SRichard Henderson msr_to_set |= MSR_BIP; 1096f5235314SRichard Henderson } 1097f5235314SRichard Henderson if (imm == 0x8 || imm == 0x18) { 1098f5235314SRichard Henderson /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */ 1099f5235314SRichard Henderson msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1; 1100f5235314SRichard Henderson tcg_gen_andi_i32(cpu_msr, cpu_msr, 1101f5235314SRichard Henderson ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM)); 1102f5235314SRichard Henderson } 1103f5235314SRichard Henderson tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set); 1104f5235314SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1105f5235314SRichard Henderson #endif 1106f5235314SRichard Henderson 1107f5235314SRichard Henderson return true; 1108f5235314SRichard Henderson } 1109f5235314SRichard Henderson 1110ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg) 1111ee8c7f9fSRichard Henderson { 1112ee8c7f9fSRichard Henderson int mbar_imm = arg->imm; 1113ee8c7f9fSRichard Henderson 1114ee8c7f9fSRichard Henderson /* Data access memory barrier. */ 1115ee8c7f9fSRichard Henderson if ((mbar_imm & 2) == 0) { 1116ee8c7f9fSRichard Henderson tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 1117ee8c7f9fSRichard Henderson } 1118ee8c7f9fSRichard Henderson 1119ee8c7f9fSRichard Henderson /* Sleep. */ 1120ee8c7f9fSRichard Henderson if (mbar_imm & 16) { 1121ee8c7f9fSRichard Henderson TCGv_i32 tmp_1; 1122ee8c7f9fSRichard Henderson 1123ee8c7f9fSRichard Henderson if (trap_userspace(dc, true)) { 1124ee8c7f9fSRichard Henderson /* Sleep is a privileged instruction. */ 1125ee8c7f9fSRichard Henderson return true; 1126ee8c7f9fSRichard Henderson } 1127ee8c7f9fSRichard Henderson 1128ee8c7f9fSRichard Henderson t_sync_flags(dc); 1129ee8c7f9fSRichard Henderson 1130ee8c7f9fSRichard Henderson tmp_1 = tcg_const_i32(1); 1131ee8c7f9fSRichard Henderson tcg_gen_st_i32(tmp_1, cpu_env, 1132ee8c7f9fSRichard Henderson -offsetof(MicroBlazeCPU, env) 1133ee8c7f9fSRichard Henderson +offsetof(CPUState, halted)); 1134ee8c7f9fSRichard Henderson tcg_temp_free_i32(tmp_1); 1135ee8c7f9fSRichard Henderson 1136ee8c7f9fSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1137ee8c7f9fSRichard Henderson 1138ee8c7f9fSRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1139ee8c7f9fSRichard Henderson } 1140ee8c7f9fSRichard Henderson 1141ee8c7f9fSRichard Henderson /* 1142ee8c7f9fSRichard Henderson * If !(mbar_imm & 1), this is an instruction access memory barrier 1143ee8c7f9fSRichard Henderson * and we need to end the TB so that we recognize self-modified 1144ee8c7f9fSRichard Henderson * code immediately. 1145ee8c7f9fSRichard Henderson * 1146ee8c7f9fSRichard Henderson * However, there are some data mbars that need the TB break 1147ee8c7f9fSRichard Henderson * (and return to main loop) to recognize interrupts right away. 1148ee8c7f9fSRichard Henderson * E.g. recognizing a change to an interrupt controller register. 1149ee8c7f9fSRichard Henderson * 1150ee8c7f9fSRichard Henderson * Therefore, choose to end the TB always. 1151ee8c7f9fSRichard Henderson */ 1152ee8c7f9fSRichard Henderson dc->cpustate_changed = 1; 1153ee8c7f9fSRichard Henderson return true; 1154ee8c7f9fSRichard Henderson } 1155ee8c7f9fSRichard Henderson 115620800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 115720800179SRichard Henderson { 115820800179SRichard Henderson /* If opcode_0_illegal, trap. */ 115920800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 116020800179SRichard Henderson trap_illegal(dc, true); 116120800179SRichard Henderson return true; 116220800179SRichard Henderson } 116320800179SRichard Henderson /* 116420800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 116520800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 116620800179SRichard Henderson */ 116720800179SRichard Henderson return false; 1168fcf5ef2aSThomas Huth } 1169fcf5ef2aSThomas Huth 11701074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 1171fcf5ef2aSThomas Huth { 11721074c0fbSRichard Henderson TCGv_i32 t; 11731074c0fbSRichard Henderson 11741074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 11751074c0fbSRichard Henderson t = tcg_temp_new_i32(); 11761074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 11771074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 11781074c0fbSRichard Henderson tcg_temp_free_i32(t); 1179fcf5ef2aSThomas Huth } 1180fcf5ef2aSThomas Huth 11811074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 1182fcf5ef2aSThomas Huth { 1183fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 11841074c0fbSRichard Henderson 11851074c0fbSRichard Henderson /* Install MSR_C. */ 11861074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 11871074c0fbSRichard Henderson 11881074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 11891074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 1190fcf5ef2aSThomas Huth } 1191fcf5ef2aSThomas Huth 1192fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc) 1193fcf5ef2aSThomas Huth { 1194fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 1195cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 11962023e9a3SEdgar E. Iglesias unsigned int sr, rn; 1197f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 1198fcf5ef2aSThomas Huth 11992023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 12002023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 12012023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 1202fcf5ef2aSThomas Huth dc->type_b = 1; 12032023e9a3SEdgar E. Iglesias if (to) { 1204fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 1205f0f7e7f7SEdgar E. Iglesias } 1206f0f7e7f7SEdgar E. Iglesias 1207f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 1208f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 1209f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 1210f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 1211f0f7e7f7SEdgar E. Iglesias 1212f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 12132023e9a3SEdgar E. Iglesias } 1214fcf5ef2aSThomas Huth 1215fcf5ef2aSThomas Huth /* msrclr and msrset. */ 12162023e9a3SEdgar E. Iglesias if (clrset) { 12172023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 1218fcf5ef2aSThomas Huth 121956837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 1220fcf5ef2aSThomas Huth /* nop??? */ 1221fcf5ef2aSThomas Huth return; 1222fcf5ef2aSThomas Huth } 1223fcf5ef2aSThomas Huth 1224bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 1225fcf5ef2aSThomas Huth return; 1226fcf5ef2aSThomas Huth } 1227fcf5ef2aSThomas Huth 1228fcf5ef2aSThomas Huth if (dc->rd) 1229fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 1230fcf5ef2aSThomas Huth 1231cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1232cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1233fcf5ef2aSThomas Huth msr_read(dc, t0); 1234cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 1235fcf5ef2aSThomas Huth 1236fcf5ef2aSThomas Huth if (clr) { 1237cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 1238cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 1239fcf5ef2aSThomas Huth } else 1240cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 1241fcf5ef2aSThomas Huth msr_write(dc, t0); 1242cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1243cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1244d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1245d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1246fcf5ef2aSThomas Huth return; 1247fcf5ef2aSThomas Huth } 1248fcf5ef2aSThomas Huth 1249bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 1250fcf5ef2aSThomas Huth return; 1251fcf5ef2aSThomas Huth } 1252fcf5ef2aSThomas Huth 1253fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 1254fcf5ef2aSThomas Huth /* Catch read/writes to the mmu block. */ 1255fcf5ef2aSThomas Huth if ((sr & ~0xff) == 0x1000) { 1256f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 125705a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 125805a9a651SEdgar E. Iglesias 1259fcf5ef2aSThomas Huth sr &= 7; 126005a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 126105a9a651SEdgar E. Iglesias if (to) { 1262f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 126305a9a651SEdgar E. Iglesias } else { 1264f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 126505a9a651SEdgar E. Iglesias } 126605a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 1267f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 1268fcf5ef2aSThomas Huth return; 1269fcf5ef2aSThomas Huth } 1270fcf5ef2aSThomas Huth #endif 1271fcf5ef2aSThomas Huth 1272fcf5ef2aSThomas Huth if (to) { 1273fcf5ef2aSThomas Huth switch (sr) { 1274aa28e6d4SRichard Henderson case SR_PC: 1275fcf5ef2aSThomas Huth break; 1276aa28e6d4SRichard Henderson case SR_MSR: 1277fcf5ef2aSThomas Huth msr_write(dc, cpu_R[dc->ra]); 1278fcf5ef2aSThomas Huth break; 1279351527b7SEdgar E. Iglesias case SR_EAR: 1280dbdb77c4SRichard Henderson { 1281dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1282dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 1283dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 1284dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1285dbdb77c4SRichard Henderson } 1286aa28e6d4SRichard Henderson break; 1287351527b7SEdgar E. Iglesias case SR_ESR: 128841ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 128941ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 1290aa28e6d4SRichard Henderson break; 1291ab6dd380SEdgar E. Iglesias case SR_FSR: 129286017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 129386017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 1294aa28e6d4SRichard Henderson break; 1295aa28e6d4SRichard Henderson case SR_BTR: 1296ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 1297ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 1298aa28e6d4SRichard Henderson break; 1299aa28e6d4SRichard Henderson case SR_EDR: 130039db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 130139db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 1302fcf5ef2aSThomas Huth break; 1303fcf5ef2aSThomas Huth case 0x800: 1304cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 1305cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 1306fcf5ef2aSThomas Huth break; 1307fcf5ef2aSThomas Huth case 0x802: 1308cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 1309cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 1310fcf5ef2aSThomas Huth break; 1311fcf5ef2aSThomas Huth default: 1312fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 1313fcf5ef2aSThomas Huth break; 1314fcf5ef2aSThomas Huth } 1315fcf5ef2aSThomas Huth } else { 1316fcf5ef2aSThomas Huth switch (sr) { 1317aa28e6d4SRichard Henderson case SR_PC: 1318d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1319fcf5ef2aSThomas Huth break; 1320aa28e6d4SRichard Henderson case SR_MSR: 1321fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 1322fcf5ef2aSThomas Huth break; 1323351527b7SEdgar E. Iglesias case SR_EAR: 1324dbdb77c4SRichard Henderson { 1325dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1326dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 1327a1b48e3aSEdgar E. Iglesias if (extended) { 1328dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 1329aa28e6d4SRichard Henderson } else { 1330dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 1331dbdb77c4SRichard Henderson } 1332dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1333a1b48e3aSEdgar E. Iglesias } 1334aa28e6d4SRichard Henderson break; 1335351527b7SEdgar E. Iglesias case SR_ESR: 133641ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 133741ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 1338aa28e6d4SRichard Henderson break; 1339351527b7SEdgar E. Iglesias case SR_FSR: 134086017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 134186017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 1342aa28e6d4SRichard Henderson break; 1343351527b7SEdgar E. Iglesias case SR_BTR: 1344ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 1345ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 1346aa28e6d4SRichard Henderson break; 13477cdae31dSTong Ho case SR_EDR: 134839db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 134939db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 1350fcf5ef2aSThomas Huth break; 1351fcf5ef2aSThomas Huth case 0x800: 1352cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 1353cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 1354fcf5ef2aSThomas Huth break; 1355fcf5ef2aSThomas Huth case 0x802: 1356cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 1357cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 1358fcf5ef2aSThomas Huth break; 1359351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 1360fcf5ef2aSThomas Huth rn = sr & 0xf; 1361cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 1362fcf5ef2aSThomas Huth cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 1363fcf5ef2aSThomas Huth break; 1364fcf5ef2aSThomas Huth default: 1365fcf5ef2aSThomas Huth cpu_abort(cs, "unknown mfs reg %x\n", sr); 1366fcf5ef2aSThomas Huth break; 1367fcf5ef2aSThomas Huth } 1368fcf5ef2aSThomas Huth } 1369fcf5ef2aSThomas Huth 1370fcf5ef2aSThomas Huth if (dc->rd == 0) { 1371cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 1372fcf5ef2aSThomas Huth } 1373fcf5ef2aSThomas Huth } 1374fcf5ef2aSThomas Huth 1375f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1376f91c60f0SEdgar E. Iglesias { 13771e521ce3SRichard Henderson dc->tb_flags_to_set |= D_FLAG; 13787b34f45fSRichard Henderson if (dc->type_b && (dc->tb_flags & IMM_FLAG)) { 13791e521ce3SRichard Henderson dc->tb_flags_to_set |= BIMM_FLAG; 13807b34f45fSRichard Henderson } 1381f91c60f0SEdgar E. Iglesias } 1382f91c60f0SEdgar E. Iglesias 1383fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc) 1384fcf5ef2aSThomas Huth { 1385*b9c58aabSRichard Henderson static const TCGCond mb_to_tcg_cc[] = { 1386*b9c58aabSRichard Henderson [CC_EQ] = TCG_COND_EQ, 1387*b9c58aabSRichard Henderson [CC_NE] = TCG_COND_NE, 1388*b9c58aabSRichard Henderson [CC_LT] = TCG_COND_LT, 1389*b9c58aabSRichard Henderson [CC_LE] = TCG_COND_LE, 1390*b9c58aabSRichard Henderson [CC_GE] = TCG_COND_GE, 1391*b9c58aabSRichard Henderson [CC_GT] = TCG_COND_GT, 1392*b9c58aabSRichard Henderson }; 1393fcf5ef2aSThomas Huth unsigned int cc; 1394fcf5ef2aSThomas Huth unsigned int dslot; 1395*b9c58aabSRichard Henderson TCGv_i32 zero, next; 1396fcf5ef2aSThomas Huth 1397fcf5ef2aSThomas Huth cc = EXTRACT_FIELD(dc->ir, 21, 23); 1398fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 25); 1399fcf5ef2aSThomas Huth 1400fcf5ef2aSThomas Huth if (dslot) { 1401f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1402fcf5ef2aSThomas Huth } 1403fcf5ef2aSThomas Huth 1404*b9c58aabSRichard Henderson dc->jmp_cond = mb_to_tcg_cc[cc]; 1405*b9c58aabSRichard Henderson 1406*b9c58aabSRichard Henderson /* Cache the condition register in cpu_bvalue across any delay slot. */ 1407*b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_bvalue, cpu_R[dc->ra]); 1408*b9c58aabSRichard Henderson 1409*b9c58aabSRichard Henderson /* Store the branch taken destination into btarget. */ 1410d7ecb757SRichard Henderson if (dc->type_b) { 1411*b9c58aabSRichard Henderson dc->jmp_dest = dc->base.pc_next + dec_alu_typeb_imm(dc); 1412*b9c58aabSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 1413fcf5ef2aSThomas Huth } else { 1414*b9c58aabSRichard Henderson dc->jmp_dest = -1; 1415*b9c58aabSRichard Henderson tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, dc->rb), 1416*b9c58aabSRichard Henderson dc->base.pc_next); 1417fcf5ef2aSThomas Huth } 1418*b9c58aabSRichard Henderson 1419*b9c58aabSRichard Henderson /* Compute the final destination into btarget. */ 1420*b9c58aabSRichard Henderson zero = tcg_const_i32(0); 1421*b9c58aabSRichard Henderson next = tcg_const_i32(dc->base.pc_next + (dslot + 1) * 4); 1422*b9c58aabSRichard Henderson tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget, 1423*b9c58aabSRichard Henderson reg_for_read(dc, dc->ra), zero, 1424*b9c58aabSRichard Henderson cpu_btarget, next); 1425*b9c58aabSRichard Henderson tcg_temp_free_i32(zero); 1426*b9c58aabSRichard Henderson tcg_temp_free_i32(next); 1427fcf5ef2aSThomas Huth } 1428fcf5ef2aSThomas Huth 1429fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc) 1430fcf5ef2aSThomas Huth { 1431ee8c7f9fSRichard Henderson unsigned int dslot, link, abs; 1432f5235314SRichard Henderson uint32_t add_pc; 1433fcf5ef2aSThomas Huth 1434fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 20); 1435fcf5ef2aSThomas Huth abs = dc->ir & (1 << 19); 1436fcf5ef2aSThomas Huth link = dc->ir & (1 << 18); 1437fcf5ef2aSThomas Huth 1438fcf5ef2aSThomas Huth if (dslot) { 1439f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1440fcf5ef2aSThomas Huth } 1441d7ecb757SRichard Henderson if (link && dc->rd) { 1442d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1443d7ecb757SRichard Henderson } 1444fcf5ef2aSThomas Huth 1445f5235314SRichard Henderson add_pc = abs ? 0 : dc->base.pc_next; 1446d7ecb757SRichard Henderson if (dc->type_b) { 1447*b9c58aabSRichard Henderson dc->jmp_dest = add_pc + dec_alu_typeb_imm(dc); 1448*b9c58aabSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest); 1449fcf5ef2aSThomas Huth } else { 1450*b9c58aabSRichard Henderson dc->jmp_dest = -1; 1451f5235314SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], add_pc); 1452d7ecb757SRichard Henderson } 1453*b9c58aabSRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 1454fcf5ef2aSThomas Huth } 1455fcf5ef2aSThomas Huth 1456fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc) 1457fcf5ef2aSThomas Huth { 1458cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1459cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1460cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 14613e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 14620a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 14630a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1464cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1465fcf5ef2aSThomas Huth 1466cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1467cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1468fcf5ef2aSThomas Huth msr_write(dc, t1); 1469cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1470cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1471fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1472fcf5ef2aSThomas Huth } 1473fcf5ef2aSThomas Huth 1474fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc) 1475fcf5ef2aSThomas Huth { 1476cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1477cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1478cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 14793e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 14800a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1481cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1482cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1483fcf5ef2aSThomas Huth 1484cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1485cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1486fcf5ef2aSThomas Huth msr_write(dc, t1); 1487cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1488cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1489fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1490fcf5ef2aSThomas Huth } 1491fcf5ef2aSThomas Huth 1492fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc) 1493fcf5ef2aSThomas Huth { 1494cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1495cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1496cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1497fcf5ef2aSThomas Huth 14983e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 14990a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1500cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1501cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1502cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1503fcf5ef2aSThomas Huth 1504cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1505cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1506fcf5ef2aSThomas Huth msr_write(dc, t1); 1507cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1508cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1509fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1510fcf5ef2aSThomas Huth } 1511fcf5ef2aSThomas Huth 1512fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc) 1513fcf5ef2aSThomas Huth { 1514fcf5ef2aSThomas Huth unsigned int b_bit, i_bit, e_bit; 1515fcf5ef2aSThomas Huth 1516fcf5ef2aSThomas Huth i_bit = dc->ir & (1 << 21); 1517fcf5ef2aSThomas Huth b_bit = dc->ir & (1 << 22); 1518fcf5ef2aSThomas Huth e_bit = dc->ir & (1 << 23); 1519fcf5ef2aSThomas Huth 1520bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1521bdfc1e88SEdgar E. Iglesias return; 1522bdfc1e88SEdgar E. Iglesias } 1523bdfc1e88SEdgar E. Iglesias 1524f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1525fcf5ef2aSThomas Huth 1526fcf5ef2aSThomas Huth if (i_bit) { 1527fcf5ef2aSThomas Huth dc->tb_flags |= DRTI_FLAG; 1528fcf5ef2aSThomas Huth } else if (b_bit) { 1529fcf5ef2aSThomas Huth dc->tb_flags |= DRTB_FLAG; 1530fcf5ef2aSThomas Huth } else if (e_bit) { 1531fcf5ef2aSThomas Huth dc->tb_flags |= DRTE_FLAG; 153211105d67SRichard Henderson } 1533fcf5ef2aSThomas Huth 1534*b9c58aabSRichard Henderson dc->jmp_cond = TCG_COND_ALWAYS; 1535*b9c58aabSRichard Henderson dc->jmp_dest = -1; 15360f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 1537fcf5ef2aSThomas Huth } 1538fcf5ef2aSThomas Huth 1539fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc) 1540fcf5ef2aSThomas Huth { 15419ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 1542fcf5ef2aSThomas Huth return; 1543fcf5ef2aSThomas Huth } 1544d4705ae0SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", 1545d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, dc->opcode); 1546fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1547fcf5ef2aSThomas Huth } 1548fcf5ef2aSThomas Huth 1549fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 1550fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc) 1551fcf5ef2aSThomas Huth { 1552fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1553fcf5ef2aSThomas Huth int ctrl; 1554fcf5ef2aSThomas Huth 1555bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 1556fcf5ef2aSThomas Huth return; 1557fcf5ef2aSThomas Huth } 1558fcf5ef2aSThomas Huth 1559cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 1560fcf5ef2aSThomas Huth if (dc->type_b) { 1561cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 1562fcf5ef2aSThomas Huth ctrl = dc->imm >> 10; 1563fcf5ef2aSThomas Huth } else { 1564cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 1565fcf5ef2aSThomas Huth ctrl = dc->imm >> 5; 1566fcf5ef2aSThomas Huth } 1567fcf5ef2aSThomas Huth 1568cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 1569fcf5ef2aSThomas Huth 1570fcf5ef2aSThomas Huth if (dc->rd == 0) { 1571fcf5ef2aSThomas Huth gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 1572fcf5ef2aSThomas Huth } else { 1573fcf5ef2aSThomas Huth gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 1574fcf5ef2aSThomas Huth } 1575cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1576cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 1577fcf5ef2aSThomas Huth } 1578fcf5ef2aSThomas Huth 1579fcf5ef2aSThomas Huth static struct decoder_info { 1580fcf5ef2aSThomas Huth struct { 1581fcf5ef2aSThomas Huth uint32_t bits; 1582fcf5ef2aSThomas Huth uint32_t mask; 1583fcf5ef2aSThomas Huth }; 1584fcf5ef2aSThomas Huth void (*dec)(DisasContext *dc); 1585fcf5ef2aSThomas Huth } decinfo[] = { 1586fcf5ef2aSThomas Huth {DEC_BR, dec_br}, 1587fcf5ef2aSThomas Huth {DEC_BCC, dec_bcc}, 1588fcf5ef2aSThomas Huth {DEC_RTS, dec_rts}, 1589fcf5ef2aSThomas Huth {DEC_MSR, dec_msr}, 1590fcf5ef2aSThomas Huth {DEC_STREAM, dec_stream}, 1591fcf5ef2aSThomas Huth {{0, 0}, dec_null} 1592fcf5ef2aSThomas Huth }; 1593fcf5ef2aSThomas Huth 159444d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir) 1595fcf5ef2aSThomas Huth { 1596fcf5ef2aSThomas Huth int i; 1597fcf5ef2aSThomas Huth 1598fcf5ef2aSThomas Huth dc->ir = ir; 1599fcf5ef2aSThomas Huth 1600fcf5ef2aSThomas Huth /* bit 2 seems to indicate insn type. */ 1601fcf5ef2aSThomas Huth dc->type_b = ir & (1 << 29); 1602fcf5ef2aSThomas Huth 1603fcf5ef2aSThomas Huth dc->opcode = EXTRACT_FIELD(ir, 26, 31); 1604fcf5ef2aSThomas Huth dc->rd = EXTRACT_FIELD(ir, 21, 25); 1605fcf5ef2aSThomas Huth dc->ra = EXTRACT_FIELD(ir, 16, 20); 1606fcf5ef2aSThomas Huth dc->rb = EXTRACT_FIELD(ir, 11, 15); 1607fcf5ef2aSThomas Huth dc->imm = EXTRACT_FIELD(ir, 0, 15); 1608fcf5ef2aSThomas Huth 1609fcf5ef2aSThomas Huth /* Large switch for all insns. */ 1610fcf5ef2aSThomas Huth for (i = 0; i < ARRAY_SIZE(decinfo); i++) { 1611fcf5ef2aSThomas Huth if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { 1612fcf5ef2aSThomas Huth decinfo[i].dec(dc); 1613fcf5ef2aSThomas Huth break; 1614fcf5ef2aSThomas Huth } 1615fcf5ef2aSThomas Huth } 1616fcf5ef2aSThomas Huth } 1617fcf5ef2aSThomas Huth 1618372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1619fcf5ef2aSThomas Huth { 1620372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1621372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1622372122e3SRichard Henderson int bound; 1623fcf5ef2aSThomas Huth 1624fcf5ef2aSThomas Huth dc->cpu = cpu; 1625683a247eSRichard Henderson dc->tb_flags = dc->base.tb->flags; 1626fcf5ef2aSThomas Huth dc->cpustate_changed = 0; 1627fcf5ef2aSThomas Huth dc->abort_at_next_insn = 0; 1628d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 162920800179SRichard Henderson dc->r0 = NULL; 163020800179SRichard Henderson dc->r0_set = false; 1631287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 1632*b9c58aabSRichard Henderson dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; 1633*b9c58aabSRichard Henderson dc->jmp_dest = -1; 1634fcf5ef2aSThomas Huth 1635372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1636372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1637fcf5ef2aSThomas Huth } 1638fcf5ef2aSThomas Huth 1639372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1640fcf5ef2aSThomas Huth { 1641fcf5ef2aSThomas Huth } 1642fcf5ef2aSThomas Huth 1643372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1644372122e3SRichard Henderson { 1645683a247eSRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1646683a247eSRichard Henderson 1647683a247eSRichard Henderson tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK); 1648683a247eSRichard Henderson dc->insn_start = tcg_last_op(); 1649372122e3SRichard Henderson } 1650fcf5ef2aSThomas Huth 1651372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1652372122e3SRichard Henderson const CPUBreakpoint *bp) 1653372122e3SRichard Henderson { 1654372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1655372122e3SRichard Henderson 1656372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1657372122e3SRichard Henderson 1658372122e3SRichard Henderson /* 1659372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1660372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1661372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1662372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1663372122e3SRichard Henderson */ 1664372122e3SRichard Henderson dc->base.pc_next += 4; 1665372122e3SRichard Henderson return true; 1666372122e3SRichard Henderson } 1667372122e3SRichard Henderson 1668372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1669372122e3SRichard Henderson { 1670372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1671372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 167244d1432bSRichard Henderson uint32_t ir; 1673372122e3SRichard Henderson 1674372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1675372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1676372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1677372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1678fcf5ef2aSThomas Huth } 1679fcf5ef2aSThomas Huth 16806f9642d7SRichard Henderson dc->tb_flags_to_set = 0; 16816f9642d7SRichard Henderson 168244d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 168344d1432bSRichard Henderson if (!decode(dc, ir)) { 168444d1432bSRichard Henderson old_decode(dc, ir); 168544d1432bSRichard Henderson } 168620800179SRichard Henderson 168720800179SRichard Henderson if (dc->r0) { 168820800179SRichard Henderson tcg_temp_free_i32(dc->r0); 168920800179SRichard Henderson dc->r0 = NULL; 169020800179SRichard Henderson dc->r0_set = false; 169120800179SRichard Henderson } 169220800179SRichard Henderson 16936f9642d7SRichard Henderson /* Discard the imm global when its contents cannot be used. */ 16946f9642d7SRichard Henderson if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { 1695d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1696372122e3SRichard Henderson } 16976f9642d7SRichard Henderson 16981e521ce3SRichard Henderson dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG); 16996f9642d7SRichard Henderson dc->tb_flags |= dc->tb_flags_to_set; 1700d4705ae0SRichard Henderson dc->base.pc_next += 4; 1701fcf5ef2aSThomas Huth 1702*b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) { 1703372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 1704fcf5ef2aSThomas Huth do_rti(dc); 1705*b9c58aabSRichard Henderson } else if (dc->tb_flags & DRTB_FLAG) { 1706fcf5ef2aSThomas Huth do_rtb(dc); 1707*b9c58aabSRichard Henderson } else if (dc->tb_flags & DRTE_FLAG) { 1708fcf5ef2aSThomas Huth do_rte(dc); 1709372122e3SRichard Henderson } 1710372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1711372122e3SRichard Henderson } 1712372122e3SRichard Henderson 1713372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1714372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1715372122e3SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1716372122e3SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1717372122e3SRichard Henderson } 1718372122e3SRichard Henderson } 1719372122e3SRichard Henderson 1720372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1721372122e3SRichard Henderson { 1722372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1723372122e3SRichard Henderson 1724372122e3SRichard Henderson assert(!dc->abort_at_next_insn); 1725372122e3SRichard Henderson 1726372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1727372122e3SRichard Henderson /* We have already exited the TB. */ 1728372122e3SRichard Henderson return; 1729372122e3SRichard Henderson } 1730372122e3SRichard Henderson 1731372122e3SRichard Henderson t_sync_flags(dc); 1732372122e3SRichard Henderson 1733372122e3SRichard Henderson switch (dc->base.is_jmp) { 1734372122e3SRichard Henderson case DISAS_TOO_MANY: 1735372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1736372122e3SRichard Henderson return; 1737372122e3SRichard Henderson 1738372122e3SRichard Henderson case DISAS_UPDATE: 1739372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1740372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1741372122e3SRichard Henderson } else { 1742372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1743372122e3SRichard Henderson } 1744372122e3SRichard Henderson return; 1745372122e3SRichard Henderson 1746372122e3SRichard Henderson case DISAS_JUMP: 1747*b9c58aabSRichard Henderson if (dc->jmp_dest != -1 && !cs->singlestep_enabled) { 1748*b9c58aabSRichard Henderson /* Direct jump. */ 1749*b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1750*b9c58aabSRichard Henderson 1751*b9c58aabSRichard Henderson if (dc->jmp_cond != TCG_COND_ALWAYS) { 1752*b9c58aabSRichard Henderson /* Conditional direct jump. */ 1753*b9c58aabSRichard Henderson TCGLabel *taken = gen_new_label(); 1754*b9c58aabSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 1755*b9c58aabSRichard Henderson 1756*b9c58aabSRichard Henderson /* 1757*b9c58aabSRichard Henderson * Copy bvalue to a temp now, so we can discard bvalue. 1758*b9c58aabSRichard Henderson * This can avoid writing bvalue to memory when the 1759*b9c58aabSRichard Henderson * delay slot cannot raise an exception. 1760*b9c58aabSRichard Henderson */ 1761*b9c58aabSRichard Henderson tcg_gen_mov_i32(tmp, cpu_bvalue); 1762*b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_bvalue); 1763*b9c58aabSRichard Henderson 1764*b9c58aabSRichard Henderson tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken); 1765*b9c58aabSRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1766*b9c58aabSRichard Henderson gen_set_label(taken); 1767*b9c58aabSRichard Henderson } 1768*b9c58aabSRichard Henderson gen_goto_tb(dc, 0, dc->jmp_dest); 1769*b9c58aabSRichard Henderson return; 1770*b9c58aabSRichard Henderson } 1771*b9c58aabSRichard Henderson 1772*b9c58aabSRichard Henderson /* Indirect jump (or direct jump w/ singlestep) */ 1773*b9c58aabSRichard Henderson tcg_gen_mov_i32(cpu_pc, cpu_btarget); 1774*b9c58aabSRichard Henderson tcg_gen_discard_i32(cpu_btarget); 1775372122e3SRichard Henderson 1776372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1777372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1778372122e3SRichard Henderson } else { 1779372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1780372122e3SRichard Henderson } 1781372122e3SRichard Henderson return; 1782372122e3SRichard Henderson 1783a2b80dbdSRichard Henderson default: 1784a2b80dbdSRichard Henderson g_assert_not_reached(); 1785fcf5ef2aSThomas Huth } 1786fcf5ef2aSThomas Huth } 1787fcf5ef2aSThomas Huth 1788372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1789372122e3SRichard Henderson { 1790372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1791372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 1792fcf5ef2aSThomas Huth } 1793372122e3SRichard Henderson 1794372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1795372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1796372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1797372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1798372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1799372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1800372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1801372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1802372122e3SRichard Henderson }; 1803372122e3SRichard Henderson 1804372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1805372122e3SRichard Henderson { 1806372122e3SRichard Henderson DisasContext dc; 1807372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 1808fcf5ef2aSThomas Huth } 1809fcf5ef2aSThomas Huth 181090c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1811fcf5ef2aSThomas Huth { 1812fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1813fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 18140c3da918SRichard Henderson uint32_t iflags; 1815fcf5ef2aSThomas Huth int i; 1816fcf5ef2aSThomas Huth 18170c3da918SRichard Henderson qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n", 18180c3da918SRichard Henderson env->pc, env->msr, 18192e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18202e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18212e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18222e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18230c3da918SRichard Henderson 18240c3da918SRichard Henderson iflags = env->iflags; 18250c3da918SRichard Henderson qemu_fprintf(f, "iflags: 0x%08x", iflags); 18260c3da918SRichard Henderson if (iflags & IMM_FLAG) { 18270c3da918SRichard Henderson qemu_fprintf(f, " IMM(0x%08x)", env->imm); 18282ead1b18SJoe Komlodi } 18290c3da918SRichard Henderson if (iflags & BIMM_FLAG) { 18300c3da918SRichard Henderson qemu_fprintf(f, " BIMM"); 18310c3da918SRichard Henderson } 18320c3da918SRichard Henderson if (iflags & D_FLAG) { 1833*b9c58aabSRichard Henderson qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget); 18340c3da918SRichard Henderson } 18350c3da918SRichard Henderson if (iflags & DRTI_FLAG) { 18360c3da918SRichard Henderson qemu_fprintf(f, " DRTI"); 18370c3da918SRichard Henderson } 18380c3da918SRichard Henderson if (iflags & DRTE_FLAG) { 18390c3da918SRichard Henderson qemu_fprintf(f, " DRTE"); 18400c3da918SRichard Henderson } 18410c3da918SRichard Henderson if (iflags & DRTB_FLAG) { 18420c3da918SRichard Henderson qemu_fprintf(f, " DRTB"); 18430c3da918SRichard Henderson } 18440c3da918SRichard Henderson if (iflags & ESR_ESS_FLAG) { 18450c3da918SRichard Henderson qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK); 18462ead1b18SJoe Komlodi } 1847fcf5ef2aSThomas Huth 18480c3da918SRichard Henderson qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" 18490c3da918SRichard Henderson "ear=0x%016" PRIx64 " slr=0x%x shr=0x%x\n", 18500c3da918SRichard Henderson env->esr, env->fsr, env->btr, env->edr, 18510c3da918SRichard Henderson env->ear, env->slr, env->shr); 18520c3da918SRichard Henderson 18530c3da918SRichard Henderson for (i = 0; i < 12; i++) { 18540c3da918SRichard Henderson qemu_fprintf(f, "rpvr%-2d=%08x%c", 18550c3da918SRichard Henderson i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' '); 1856fcf5ef2aSThomas Huth } 18570c3da918SRichard Henderson 18580c3da918SRichard Henderson for (i = 0; i < 32; i++) { 18590c3da918SRichard Henderson qemu_fprintf(f, "r%2.2d=%08x%c", 18600c3da918SRichard Henderson i, env->regs[i], i % 4 == 3 ? '\n' : ' '); 18610c3da918SRichard Henderson } 18620c3da918SRichard Henderson qemu_fprintf(f, "\n"); 1863fcf5ef2aSThomas Huth } 1864fcf5ef2aSThomas Huth 1865fcf5ef2aSThomas Huth void mb_tcg_init(void) 1866fcf5ef2aSThomas Huth { 1867480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1868480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1869fcf5ef2aSThomas Huth 1870480d29a8SRichard Henderson static const struct { 1871480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1872480d29a8SRichard Henderson } i32s[] = { 1873480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1874480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1875480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1876480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1877480d29a8SRichard Henderson 1878480d29a8SRichard Henderson SP(pc), 1879480d29a8SRichard Henderson SP(msr), 18801074c0fbSRichard Henderson SP(msr_c), 1881480d29a8SRichard Henderson SP(imm), 1882480d29a8SRichard Henderson SP(iflags), 1883*b9c58aabSRichard Henderson SP(bvalue), 1884480d29a8SRichard Henderson SP(btarget), 1885480d29a8SRichard Henderson SP(res_val), 1886480d29a8SRichard Henderson }; 1887480d29a8SRichard Henderson 1888480d29a8SRichard Henderson #undef R 1889480d29a8SRichard Henderson #undef SP 1890480d29a8SRichard Henderson 1891480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1892480d29a8SRichard Henderson *i32s[i].var = 1893480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1894fcf5ef2aSThomas Huth } 189576e8187dSRichard Henderson 1896480d29a8SRichard Henderson cpu_res_addr = 1897480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1898fcf5ef2aSThomas Huth } 1899fcf5ef2aSThomas Huth 1900fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1901fcf5ef2aSThomas Huth target_ulong *data) 1902fcf5ef2aSThomas Huth { 190376e8187dSRichard Henderson env->pc = data[0]; 1904683a247eSRichard Henderson env->iflags = data[1]; 1905fcf5ef2aSThomas Huth } 1906