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; 489b158558SRichard Henderson static TCGv_i32 cpu_btaken; 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 6120800179SRichard Henderson TCGv_i32 r0; 6220800179SRichard Henderson bool r0_set; 6320800179SRichard Henderson 64fcf5ef2aSThomas Huth /* Decoder. */ 65fcf5ef2aSThomas Huth int type_b; 66fcf5ef2aSThomas Huth uint32_t ir; 67d7ecb757SRichard Henderson uint32_t ext_imm; 68fcf5ef2aSThomas Huth uint8_t opcode; 69fcf5ef2aSThomas Huth uint8_t rd, ra, rb; 70fcf5ef2aSThomas Huth uint16_t imm; 71fcf5ef2aSThomas Huth 72fcf5ef2aSThomas Huth unsigned int cpustate_changed; 73fcf5ef2aSThomas Huth unsigned int delayed_branch; 74fcf5ef2aSThomas Huth unsigned int tb_flags, synced_flags; /* tb dependent flags. */ 75fcf5ef2aSThomas Huth unsigned int clear_imm; 76fcf5ef2aSThomas Huth 77fcf5ef2aSThomas Huth #define JMP_NOJMP 0 78fcf5ef2aSThomas Huth #define JMP_DIRECT 1 79fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2 80fcf5ef2aSThomas Huth #define JMP_INDIRECT 3 81fcf5ef2aSThomas Huth unsigned int jmp; 82fcf5ef2aSThomas Huth uint32_t jmp_pc; 83fcf5ef2aSThomas Huth 84fcf5ef2aSThomas Huth int abort_at_next_insn; 85fcf5ef2aSThomas Huth } DisasContext; 86fcf5ef2aSThomas Huth 8720800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8820800179SRichard Henderson { 8920800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 9020800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 9120800179SRichard Henderson } 9220800179SRichard Henderson return x; 9320800179SRichard Henderson } 9420800179SRichard Henderson 9544d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9644d1432bSRichard Henderson #include "decode-insns.c.inc" 9744d1432bSRichard Henderson 98fcf5ef2aSThomas Huth static inline void t_sync_flags(DisasContext *dc) 99fcf5ef2aSThomas Huth { 100fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 101fcf5ef2aSThomas Huth if (dc->tb_flags != dc->synced_flags) { 1029b158558SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags); 103fcf5ef2aSThomas Huth dc->synced_flags = dc->tb_flags; 104fcf5ef2aSThomas Huth } 105fcf5ef2aSThomas Huth } 106fcf5ef2aSThomas Huth 10741ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 108fcf5ef2aSThomas Huth { 109fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 110fcf5ef2aSThomas Huth 111fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 112fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 113d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 114fcf5ef2aSThomas Huth } 115fcf5ef2aSThomas Huth 11641ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11741ba37c4SRichard Henderson { 11841ba37c4SRichard Henderson t_sync_flags(dc); 119d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 12041ba37c4SRichard Henderson gen_raise_exception(dc, index); 12141ba37c4SRichard Henderson } 12241ba37c4SRichard Henderson 12341ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12441ba37c4SRichard Henderson { 12541ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12641ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12741ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12841ba37c4SRichard Henderson 12941ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 13041ba37c4SRichard Henderson } 13141ba37c4SRichard Henderson 132fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 133fcf5ef2aSThomas Huth { 134fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 135d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 136fcf5ef2aSThomas Huth #else 137fcf5ef2aSThomas Huth return true; 138fcf5ef2aSThomas Huth #endif 139fcf5ef2aSThomas Huth } 140fcf5ef2aSThomas Huth 141fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 142fcf5ef2aSThomas Huth { 143d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1440b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1450b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1460b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1470b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1480b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 149fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1500f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 151d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 152fcf5ef2aSThomas Huth } else { 1530f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 15407ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 155fcf5ef2aSThomas Huth } 156d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 157fcf5ef2aSThomas Huth } 158fcf5ef2aSThomas Huth 159bdfc1e88SEdgar E. Iglesias /* 1609ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1619ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1629ba8cd45SEdgar E. Iglesias */ 1639ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1649ba8cd45SEdgar E. Iglesias { 1659ba8cd45SEdgar E. Iglesias if (cond && (dc->tb_flags & MSR_EE_FLAG) 1665143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 16741ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1689ba8cd45SEdgar E. Iglesias } 1699ba8cd45SEdgar E. Iglesias return cond; 1709ba8cd45SEdgar E. Iglesias } 1719ba8cd45SEdgar E. Iglesias 1729ba8cd45SEdgar E. Iglesias /* 173bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 174bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 175bdfc1e88SEdgar E. Iglesias */ 176bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 177bdfc1e88SEdgar E. Iglesias { 178bdfc1e88SEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 179bdfc1e88SEdgar E. Iglesias bool cond_user = cond && mem_index == MMU_USER_IDX; 180bdfc1e88SEdgar E. Iglesias 181bdfc1e88SEdgar E. Iglesias if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { 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 321*d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 322*d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 323*d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 324*d5aead3dSRichard Henderson 325*d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 326*d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 327*d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 328*d5aead3dSRichard 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 475*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 476*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 477*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 478*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 479*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 480*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 481*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 482*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 483*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 484*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 485*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 486*d5aead3dSRichard Henderson 487*d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 488*d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 489*d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 490*d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 491*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 492*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 493*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 494*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 495*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 496*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 497*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 498*d5aead3dSRichard Henderson 499*d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 500*d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 501*d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 502*d5aead3dSRichard Henderson 503*d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 504*d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 505*d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 506*d5aead3dSRichard Henderson 507*d5aead3dSRichard 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); 525e64b2e5cSRichard Henderson dc->tb_flags |= IMM_FLAG; 526e64b2e5cSRichard Henderson dc->clear_imm = 0; 527e64b2e5cSRichard Henderson return true; 528e64b2e5cSRichard Henderson } 529e64b2e5cSRichard Henderson 53097955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 53197955cebSRichard Henderson { 53297955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 53397955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 53497955cebSRichard Henderson tcg_temp_free_i32(tmp); 53597955cebSRichard Henderson } 53697955cebSRichard Henderson 53797955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 53897955cebSRichard Henderson { 53997955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 54097955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 54197955cebSRichard Henderson tcg_temp_free_i32(tmp); 54297955cebSRichard Henderson } 54397955cebSRichard Henderson 54497955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 54597955cebSRichard Henderson { 54697955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 54797955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 54897955cebSRichard Henderson tcg_temp_free_i32(tmp); 54997955cebSRichard Henderson } 55097955cebSRichard Henderson 55197955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 55297955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 55397955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 55497955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 55597955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 55697955cebSRichard Henderson 557cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 558cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 559cb0a0a4cSRichard Henderson 560607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 561607f5767SRichard Henderson { 562607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 563607f5767SRichard Henderson } 564607f5767SRichard Henderson 565607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 566607f5767SRichard Henderson { 567607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 568607f5767SRichard Henderson } 569607f5767SRichard Henderson 570607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 571607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 572607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 573607f5767SRichard Henderson 574a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 575a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 576a2b0b90eSRichard Henderson { 577a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 578a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 579a2b0b90eSRichard Henderson } 580a2b0b90eSRichard Henderson 581a2b0b90eSRichard Henderson /* Input and output carry. */ 582a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 583a2b0b90eSRichard Henderson { 584a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 585a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 586a2b0b90eSRichard Henderson 587a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 588a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 589a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 590a2b0b90eSRichard Henderson 591a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 592a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 593a2b0b90eSRichard Henderson } 594a2b0b90eSRichard Henderson 595a2b0b90eSRichard Henderson /* No input or output carry. */ 596a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 597a2b0b90eSRichard Henderson { 598a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 599a2b0b90eSRichard Henderson } 600a2b0b90eSRichard Henderson 601a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 602a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 603a2b0b90eSRichard Henderson { 604a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 605a2b0b90eSRichard Henderson 606a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 607a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 608a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 609a2b0b90eSRichard Henderson 610a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 611a2b0b90eSRichard Henderson } 612a2b0b90eSRichard Henderson 613a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 614a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 615a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 616a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 617a2b0b90eSRichard Henderson 618a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 619a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 620a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 621a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 622a2b0b90eSRichard Henderson 62339cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 62439cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 62539cf3864SRichard Henderson 62639cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 62739cf3864SRichard Henderson { 62839cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 62939cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 63039cf3864SRichard Henderson } 63139cf3864SRichard Henderson 63239cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 63339cf3864SRichard Henderson { 63439cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 63539cf3864SRichard Henderson 63639cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 63739cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 63839cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 63939cf3864SRichard Henderson 64039cf3864SRichard Henderson tcg_temp_free_i32(tmp); 64139cf3864SRichard Henderson } 64239cf3864SRichard Henderson 64339cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 64439cf3864SRichard Henderson { 64539cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 64639cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 64739cf3864SRichard Henderson } 64839cf3864SRichard Henderson 64939cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 65039cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 65139cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 65239cf3864SRichard Henderson 65339cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 65439cf3864SRichard Henderson { 65539cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 65639cf3864SRichard Henderson } 65739cf3864SRichard Henderson 65839cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 65939cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 66039cf3864SRichard Henderson 66139cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 66239cf3864SRichard Henderson { 66339cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 66439cf3864SRichard Henderson trap_userspace(dc, true); 66539cf3864SRichard Henderson return true; 66639cf3864SRichard Henderson } 66739cf3864SRichard Henderson 668cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 669cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 670cb0a0a4cSRichard Henderson 67120800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 67220800179SRichard Henderson { 67320800179SRichard Henderson /* If opcode_0_illegal, trap. */ 67420800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 67520800179SRichard Henderson trap_illegal(dc, true); 67620800179SRichard Henderson return true; 67720800179SRichard Henderson } 67820800179SRichard Henderson /* 67920800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 68020800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 68120800179SRichard Henderson */ 68220800179SRichard Henderson return false; 683fcf5ef2aSThomas Huth } 684fcf5ef2aSThomas Huth 6851074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 686fcf5ef2aSThomas Huth { 6871074c0fbSRichard Henderson TCGv_i32 t; 6881074c0fbSRichard Henderson 6891074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 6901074c0fbSRichard Henderson t = tcg_temp_new_i32(); 6911074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 6921074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 6931074c0fbSRichard Henderson tcg_temp_free_i32(t); 694fcf5ef2aSThomas Huth } 695fcf5ef2aSThomas Huth 6961074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 697fcf5ef2aSThomas Huth { 698fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 6991074c0fbSRichard Henderson 7001074c0fbSRichard Henderson /* Install MSR_C. */ 7011074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 7021074c0fbSRichard Henderson 7031074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 7041074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 705fcf5ef2aSThomas Huth } 706fcf5ef2aSThomas Huth 707fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc) 708fcf5ef2aSThomas Huth { 709fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 710cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 7112023e9a3SEdgar E. Iglesias unsigned int sr, rn; 712f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 713fcf5ef2aSThomas Huth 7142023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 7152023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 7162023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 717fcf5ef2aSThomas Huth dc->type_b = 1; 7182023e9a3SEdgar E. Iglesias if (to) { 719fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 720f0f7e7f7SEdgar E. Iglesias } 721f0f7e7f7SEdgar E. Iglesias 722f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 723f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 724f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 725f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 726f0f7e7f7SEdgar E. Iglesias 727f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 7282023e9a3SEdgar E. Iglesias } 729fcf5ef2aSThomas Huth 730fcf5ef2aSThomas Huth /* msrclr and msrset. */ 7312023e9a3SEdgar E. Iglesias if (clrset) { 7322023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 733fcf5ef2aSThomas Huth 73456837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 735fcf5ef2aSThomas Huth /* nop??? */ 736fcf5ef2aSThomas Huth return; 737fcf5ef2aSThomas Huth } 738fcf5ef2aSThomas Huth 739bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 740fcf5ef2aSThomas Huth return; 741fcf5ef2aSThomas Huth } 742fcf5ef2aSThomas Huth 743fcf5ef2aSThomas Huth if (dc->rd) 744fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 745fcf5ef2aSThomas Huth 746cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 747cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 748fcf5ef2aSThomas Huth msr_read(dc, t0); 749cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 750fcf5ef2aSThomas Huth 751fcf5ef2aSThomas Huth if (clr) { 752cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 753cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 754fcf5ef2aSThomas Huth } else 755cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 756fcf5ef2aSThomas Huth msr_write(dc, t0); 757cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 758cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 759d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 760d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 761fcf5ef2aSThomas Huth return; 762fcf5ef2aSThomas Huth } 763fcf5ef2aSThomas Huth 764bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 765fcf5ef2aSThomas Huth return; 766fcf5ef2aSThomas Huth } 767fcf5ef2aSThomas Huth 768fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 769fcf5ef2aSThomas Huth /* Catch read/writes to the mmu block. */ 770fcf5ef2aSThomas Huth if ((sr & ~0xff) == 0x1000) { 771f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 77205a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 77305a9a651SEdgar E. Iglesias 774fcf5ef2aSThomas Huth sr &= 7; 77505a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 77605a9a651SEdgar E. Iglesias if (to) { 777f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 77805a9a651SEdgar E. Iglesias } else { 779f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 78005a9a651SEdgar E. Iglesias } 78105a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 782f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 783fcf5ef2aSThomas Huth return; 784fcf5ef2aSThomas Huth } 785fcf5ef2aSThomas Huth #endif 786fcf5ef2aSThomas Huth 787fcf5ef2aSThomas Huth if (to) { 788fcf5ef2aSThomas Huth switch (sr) { 789aa28e6d4SRichard Henderson case SR_PC: 790fcf5ef2aSThomas Huth break; 791aa28e6d4SRichard Henderson case SR_MSR: 792fcf5ef2aSThomas Huth msr_write(dc, cpu_R[dc->ra]); 793fcf5ef2aSThomas Huth break; 794351527b7SEdgar E. Iglesias case SR_EAR: 795dbdb77c4SRichard Henderson { 796dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 797dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 798dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 799dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 800dbdb77c4SRichard Henderson } 801aa28e6d4SRichard Henderson break; 802351527b7SEdgar E. Iglesias case SR_ESR: 80341ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 80441ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 805aa28e6d4SRichard Henderson break; 806ab6dd380SEdgar E. Iglesias case SR_FSR: 80786017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 80886017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 809aa28e6d4SRichard Henderson break; 810aa28e6d4SRichard Henderson case SR_BTR: 811ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 812ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 813aa28e6d4SRichard Henderson break; 814aa28e6d4SRichard Henderson case SR_EDR: 81539db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 81639db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 817fcf5ef2aSThomas Huth break; 818fcf5ef2aSThomas Huth case 0x800: 819cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 820cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 821fcf5ef2aSThomas Huth break; 822fcf5ef2aSThomas Huth case 0x802: 823cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 824cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 825fcf5ef2aSThomas Huth break; 826fcf5ef2aSThomas Huth default: 827fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 828fcf5ef2aSThomas Huth break; 829fcf5ef2aSThomas Huth } 830fcf5ef2aSThomas Huth } else { 831fcf5ef2aSThomas Huth switch (sr) { 832aa28e6d4SRichard Henderson case SR_PC: 833d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 834fcf5ef2aSThomas Huth break; 835aa28e6d4SRichard Henderson case SR_MSR: 836fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 837fcf5ef2aSThomas Huth break; 838351527b7SEdgar E. Iglesias case SR_EAR: 839dbdb77c4SRichard Henderson { 840dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 841dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 842a1b48e3aSEdgar E. Iglesias if (extended) { 843dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 844aa28e6d4SRichard Henderson } else { 845dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 846dbdb77c4SRichard Henderson } 847dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 848a1b48e3aSEdgar E. Iglesias } 849aa28e6d4SRichard Henderson break; 850351527b7SEdgar E. Iglesias case SR_ESR: 85141ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 85241ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 853aa28e6d4SRichard Henderson break; 854351527b7SEdgar E. Iglesias case SR_FSR: 85586017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 85686017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 857aa28e6d4SRichard Henderson break; 858351527b7SEdgar E. Iglesias case SR_BTR: 859ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 860ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 861aa28e6d4SRichard Henderson break; 8627cdae31dSTong Ho case SR_EDR: 86339db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 86439db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 865fcf5ef2aSThomas Huth break; 866fcf5ef2aSThomas Huth case 0x800: 867cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 868cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 869fcf5ef2aSThomas Huth break; 870fcf5ef2aSThomas Huth case 0x802: 871cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 872cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 873fcf5ef2aSThomas Huth break; 874351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 875fcf5ef2aSThomas Huth rn = sr & 0xf; 876cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 877fcf5ef2aSThomas Huth cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 878fcf5ef2aSThomas Huth break; 879fcf5ef2aSThomas Huth default: 880fcf5ef2aSThomas Huth cpu_abort(cs, "unknown mfs reg %x\n", sr); 881fcf5ef2aSThomas Huth break; 882fcf5ef2aSThomas Huth } 883fcf5ef2aSThomas Huth } 884fcf5ef2aSThomas Huth 885fcf5ef2aSThomas Huth if (dc->rd == 0) { 886cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 887fcf5ef2aSThomas Huth } 888fcf5ef2aSThomas Huth } 889fcf5ef2aSThomas Huth 890fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc) 891fcf5ef2aSThomas Huth { 892fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 893fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT) { 8949b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 895fcf5ef2aSThomas Huth } 896fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 8970f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 898fcf5ef2aSThomas Huth } 899fcf5ef2aSThomas Huth } 900fcf5ef2aSThomas Huth 901d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) 902fcf5ef2aSThomas Huth { 9030e9033c8SEdgar E. Iglesias /* Should be set to true if r1 is used by loadstores. */ 9040e9033c8SEdgar E. Iglesias bool stackprot = false; 905403322eaSEdgar E. Iglesias TCGv_i32 t32; 906fcf5ef2aSThomas Huth 907fcf5ef2aSThomas Huth /* All load/stores use ra. */ 908fcf5ef2aSThomas Huth if (dc->ra == 1 && dc->cpu->cfg.stackprot) { 9090e9033c8SEdgar E. Iglesias stackprot = true; 910fcf5ef2aSThomas Huth } 911fcf5ef2aSThomas Huth 912fcf5ef2aSThomas Huth /* Treat the common cases first. */ 913fcf5ef2aSThomas Huth if (!dc->type_b) { 914d248e1beSEdgar E. Iglesias if (ea) { 915d248e1beSEdgar E. Iglesias int addr_size = dc->cpu->cfg.addr_size; 916d248e1beSEdgar E. Iglesias 917d248e1beSEdgar E. Iglesias if (addr_size == 32) { 918d248e1beSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 919d248e1beSEdgar E. Iglesias return; 920d248e1beSEdgar E. Iglesias } 921d248e1beSEdgar E. Iglesias 922d248e1beSEdgar E. Iglesias tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]); 923d248e1beSEdgar E. Iglesias if (addr_size < 64) { 924d248e1beSEdgar E. Iglesias /* Mask off out of range bits. */ 925d248e1beSEdgar E. Iglesias tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size)); 926d248e1beSEdgar E. Iglesias } 927d248e1beSEdgar E. Iglesias return; 928d248e1beSEdgar E. Iglesias } 929d248e1beSEdgar E. Iglesias 9300dc4af5cSEdgar E. Iglesias /* If any of the regs is r0, set t to the value of the other reg. */ 931fcf5ef2aSThomas Huth if (dc->ra == 0) { 932403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 9330dc4af5cSEdgar E. Iglesias return; 934fcf5ef2aSThomas Huth } else if (dc->rb == 0) { 935403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]); 9360dc4af5cSEdgar E. Iglesias return; 937fcf5ef2aSThomas Huth } 938fcf5ef2aSThomas Huth 939fcf5ef2aSThomas Huth if (dc->rb == 1 && dc->cpu->cfg.stackprot) { 9400e9033c8SEdgar E. Iglesias stackprot = true; 941fcf5ef2aSThomas Huth } 942fcf5ef2aSThomas Huth 943403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 944403322eaSEdgar E. Iglesias tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]); 945403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 946403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 947fcf5ef2aSThomas Huth 948fcf5ef2aSThomas Huth if (stackprot) { 9490a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 950fcf5ef2aSThomas Huth } 9510dc4af5cSEdgar E. Iglesias return; 952fcf5ef2aSThomas Huth } 953fcf5ef2aSThomas Huth /* Immediate. */ 954403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 955d7ecb757SRichard Henderson tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc)); 956403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 957403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 958fcf5ef2aSThomas Huth 959fcf5ef2aSThomas Huth if (stackprot) { 9600a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 961fcf5ef2aSThomas Huth } 9620dc4af5cSEdgar E. Iglesias return; 963fcf5ef2aSThomas Huth } 964fcf5ef2aSThomas Huth 965fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc) 966fcf5ef2aSThomas Huth { 967403322eaSEdgar E. Iglesias TCGv_i32 v; 968403322eaSEdgar E. Iglesias TCGv addr; 9698534063aSEdgar E. Iglesias unsigned int size; 970d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 971d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 97214776ab5STony Nguyen MemOp mop; 973fcf5ef2aSThomas Huth 974fcf5ef2aSThomas Huth mop = dc->opcode & 3; 975fcf5ef2aSThomas Huth size = 1 << mop; 976fcf5ef2aSThomas Huth if (!dc->type_b) { 977d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 9788534063aSEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 9798534063aSEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 980fcf5ef2aSThomas Huth } 981fcf5ef2aSThomas Huth mop |= MO_TE; 982fcf5ef2aSThomas Huth if (rev) { 983fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 984fcf5ef2aSThomas Huth } 985fcf5ef2aSThomas Huth 9869ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 987fcf5ef2aSThomas Huth return; 988fcf5ef2aSThomas Huth } 989fcf5ef2aSThomas Huth 990d248e1beSEdgar E. Iglesias if (trap_userspace(dc, ea)) { 991d248e1beSEdgar E. Iglesias return; 992d248e1beSEdgar E. Iglesias } 993d248e1beSEdgar E. Iglesias 994fcf5ef2aSThomas Huth t_sync_flags(dc); 995403322eaSEdgar E. Iglesias addr = tcg_temp_new(); 996d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 997d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 998d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 999fcf5ef2aSThomas Huth 1000fcf5ef2aSThomas Huth /* 1001fcf5ef2aSThomas Huth * When doing reverse accesses we need to do two things. 1002fcf5ef2aSThomas Huth * 1003fcf5ef2aSThomas Huth * 1. Reverse the address wrt endianness. 1004fcf5ef2aSThomas Huth * 2. Byteswap the data lanes on the way back into the CPU core. 1005fcf5ef2aSThomas Huth */ 1006fcf5ef2aSThomas Huth if (rev && size != 4) { 1007fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 1008fcf5ef2aSThomas Huth switch (size) { 1009fcf5ef2aSThomas Huth case 1: 1010fcf5ef2aSThomas Huth { 1011a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 1012fcf5ef2aSThomas Huth break; 1013fcf5ef2aSThomas Huth } 1014fcf5ef2aSThomas Huth 1015fcf5ef2aSThomas Huth case 2: 1016fcf5ef2aSThomas Huth /* 00 -> 10 1017fcf5ef2aSThomas Huth 10 -> 00. */ 1018403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 1019fcf5ef2aSThomas Huth break; 1020fcf5ef2aSThomas Huth default: 1021fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 1022fcf5ef2aSThomas Huth break; 1023fcf5ef2aSThomas Huth } 1024fcf5ef2aSThomas Huth } 1025fcf5ef2aSThomas Huth 1026fcf5ef2aSThomas Huth /* lwx does not throw unaligned access errors, so force alignment */ 1027fcf5ef2aSThomas Huth if (ex) { 1028403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 1029fcf5ef2aSThomas Huth } 1030fcf5ef2aSThomas Huth 1031fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 1032fcf5ef2aSThomas Huth sync_jmpstate(dc); 1033fcf5ef2aSThomas Huth 1034fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 1035fcf5ef2aSThomas Huth /* 1036fcf5ef2aSThomas Huth * Microblaze gives MMU faults priority over faults due to 1037fcf5ef2aSThomas Huth * unaligned addresses. That's why we speculatively do the load 1038fcf5ef2aSThomas Huth * into v. If the load succeeds, we verify alignment of the 1039fcf5ef2aSThomas Huth * address and if that succeeds we write into the destination reg. 1040fcf5ef2aSThomas Huth */ 1041cfeea807SEdgar E. Iglesias v = tcg_temp_new_i32(); 1042d248e1beSEdgar E. Iglesias tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); 1043fcf5ef2aSThomas Huth 10441507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1045a6338015SEdgar E. Iglesias TCGv_i32 t0 = tcg_const_i32(0); 1046a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1047a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1048a6338015SEdgar E. Iglesias 1049d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1050a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t0, tsize); 1051a6338015SEdgar E. Iglesias 1052a6338015SEdgar E. Iglesias tcg_temp_free_i32(t0); 1053a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1054a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1055fcf5ef2aSThomas Huth } 1056fcf5ef2aSThomas Huth 1057fcf5ef2aSThomas Huth if (ex) { 10589b158558SRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 10599b158558SRichard Henderson tcg_gen_mov_i32(cpu_res_val, v); 1060fcf5ef2aSThomas Huth } 1061fcf5ef2aSThomas Huth if (dc->rd) { 1062cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(cpu_R[dc->rd], v); 1063fcf5ef2aSThomas Huth } 1064cfeea807SEdgar E. Iglesias tcg_temp_free_i32(v); 1065fcf5ef2aSThomas Huth 1066fcf5ef2aSThomas Huth if (ex) { /* lwx */ 1067fcf5ef2aSThomas Huth /* no support for AXI exclusive so always clear C */ 10681074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1069fcf5ef2aSThomas Huth } 1070fcf5ef2aSThomas Huth 1071403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1072fcf5ef2aSThomas Huth } 1073fcf5ef2aSThomas Huth 1074fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc) 1075fcf5ef2aSThomas Huth { 1076403322eaSEdgar E. Iglesias TCGv addr; 1077fcf5ef2aSThomas Huth TCGLabel *swx_skip = NULL; 1078b51b3d43SEdgar E. Iglesias unsigned int size; 1079d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 1080d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 108114776ab5STony Nguyen MemOp mop; 1082fcf5ef2aSThomas Huth 1083fcf5ef2aSThomas Huth mop = dc->opcode & 3; 1084fcf5ef2aSThomas Huth size = 1 << mop; 1085fcf5ef2aSThomas Huth if (!dc->type_b) { 1086d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 1087b51b3d43SEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 1088b51b3d43SEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 1089fcf5ef2aSThomas Huth } 1090fcf5ef2aSThomas Huth mop |= MO_TE; 1091fcf5ef2aSThomas Huth if (rev) { 1092fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 1093fcf5ef2aSThomas Huth } 1094fcf5ef2aSThomas Huth 10959ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 1096fcf5ef2aSThomas Huth return; 1097fcf5ef2aSThomas Huth } 1098fcf5ef2aSThomas Huth 1099d248e1beSEdgar E. Iglesias trap_userspace(dc, ea); 1100d248e1beSEdgar E. Iglesias 1101fcf5ef2aSThomas Huth t_sync_flags(dc); 1102fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 1103fcf5ef2aSThomas Huth sync_jmpstate(dc); 11040dc4af5cSEdgar E. Iglesias /* SWX needs a temp_local. */ 1105403322eaSEdgar E. Iglesias addr = ex ? tcg_temp_local_new() : tcg_temp_new(); 1106d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 1107d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 1108d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 1109fcf5ef2aSThomas Huth 1110fcf5ef2aSThomas Huth if (ex) { /* swx */ 1111cfeea807SEdgar E. Iglesias TCGv_i32 tval; 1112fcf5ef2aSThomas Huth 1113fcf5ef2aSThomas Huth /* swx does not throw unaligned access errors, so force alignment */ 1114403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 1115fcf5ef2aSThomas Huth 11161074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1117fcf5ef2aSThomas Huth swx_skip = gen_new_label(); 11189b158558SRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); 1119fcf5ef2aSThomas Huth 1120071cdc67SEdgar E. Iglesias /* 1121071cdc67SEdgar E. Iglesias * Compare the value loaded at lwx with current contents of 1122071cdc67SEdgar E. Iglesias * the reserved location. 1123071cdc67SEdgar E. Iglesias */ 1124cfeea807SEdgar E. Iglesias tval = tcg_temp_new_i32(); 1125071cdc67SEdgar E. Iglesias 11269b158558SRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val, 1127071cdc67SEdgar E. Iglesias cpu_R[dc->rd], mem_index, 1128071cdc67SEdgar E. Iglesias mop); 1129071cdc67SEdgar E. Iglesias 11309b158558SRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); 11311074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1132cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tval); 1133fcf5ef2aSThomas Huth } 1134fcf5ef2aSThomas Huth 1135fcf5ef2aSThomas Huth if (rev && size != 4) { 1136fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 1137fcf5ef2aSThomas Huth switch (size) { 1138fcf5ef2aSThomas Huth case 1: 1139fcf5ef2aSThomas Huth { 1140a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 1141fcf5ef2aSThomas Huth break; 1142fcf5ef2aSThomas Huth } 1143fcf5ef2aSThomas Huth 1144fcf5ef2aSThomas Huth case 2: 1145fcf5ef2aSThomas Huth /* 00 -> 10 1146fcf5ef2aSThomas Huth 10 -> 00. */ 1147fcf5ef2aSThomas Huth /* Force addr into the temp. */ 1148403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 1149fcf5ef2aSThomas Huth break; 1150fcf5ef2aSThomas Huth default: 1151fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 1152fcf5ef2aSThomas Huth break; 1153fcf5ef2aSThomas Huth } 1154fcf5ef2aSThomas Huth } 1155071cdc67SEdgar E. Iglesias 1156071cdc67SEdgar E. Iglesias if (!ex) { 1157d248e1beSEdgar E. Iglesias tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); 1158071cdc67SEdgar E. Iglesias } 1159fcf5ef2aSThomas Huth 1160fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 11611507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1162a6338015SEdgar E. Iglesias TCGv_i32 t1 = tcg_const_i32(1); 1163a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1164a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1165a6338015SEdgar E. Iglesias 1166d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1167fcf5ef2aSThomas Huth /* FIXME: if the alignment is wrong, we should restore the value 1168fcf5ef2aSThomas Huth * in memory. One possible way to achieve this is to probe 1169fcf5ef2aSThomas Huth * the MMU prior to the memaccess, thay way we could put 1170fcf5ef2aSThomas Huth * the alignment checks in between the probe and the mem 1171fcf5ef2aSThomas Huth * access. 1172fcf5ef2aSThomas Huth */ 1173a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t1, tsize); 1174a6338015SEdgar E. Iglesias 1175a6338015SEdgar E. Iglesias tcg_temp_free_i32(t1); 1176a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1177a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1178fcf5ef2aSThomas Huth } 1179fcf5ef2aSThomas Huth 1180fcf5ef2aSThomas Huth if (ex) { 1181fcf5ef2aSThomas Huth gen_set_label(swx_skip); 1182fcf5ef2aSThomas Huth } 1183fcf5ef2aSThomas Huth 1184403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1185fcf5ef2aSThomas Huth } 1186fcf5ef2aSThomas Huth 1187fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc, 11889e6e1828SEdgar E. Iglesias TCGv_i32 d, TCGv_i32 a) 1189fcf5ef2aSThomas Huth { 1190d89b86e9SEdgar E. Iglesias static const int mb_to_tcg_cc[] = { 1191d89b86e9SEdgar E. Iglesias [CC_EQ] = TCG_COND_EQ, 1192d89b86e9SEdgar E. Iglesias [CC_NE] = TCG_COND_NE, 1193d89b86e9SEdgar E. Iglesias [CC_LT] = TCG_COND_LT, 1194d89b86e9SEdgar E. Iglesias [CC_LE] = TCG_COND_LE, 1195d89b86e9SEdgar E. Iglesias [CC_GE] = TCG_COND_GE, 1196d89b86e9SEdgar E. Iglesias [CC_GT] = TCG_COND_GT, 1197d89b86e9SEdgar E. Iglesias }; 1198d89b86e9SEdgar E. Iglesias 1199fcf5ef2aSThomas Huth switch (cc) { 1200fcf5ef2aSThomas Huth case CC_EQ: 1201fcf5ef2aSThomas Huth case CC_NE: 1202fcf5ef2aSThomas Huth case CC_LT: 1203fcf5ef2aSThomas Huth case CC_LE: 1204fcf5ef2aSThomas Huth case CC_GE: 1205fcf5ef2aSThomas Huth case CC_GT: 12069e6e1828SEdgar E. Iglesias tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); 1207fcf5ef2aSThomas Huth break; 1208fcf5ef2aSThomas Huth default: 1209fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); 1210fcf5ef2aSThomas Huth break; 1211fcf5ef2aSThomas Huth } 1212fcf5ef2aSThomas Huth } 1213fcf5ef2aSThomas Huth 12140f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) 1215fcf5ef2aSThomas Huth { 12160f96e96bSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 1217e956caf2SEdgar E. Iglesias 12180f96e96bSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, 12199b158558SRichard Henderson cpu_btaken, zero, 1220e956caf2SEdgar E. Iglesias pc_true, pc_false); 1221e956caf2SEdgar E. Iglesias 12220f96e96bSRichard Henderson tcg_temp_free_i32(zero); 1223fcf5ef2aSThomas Huth } 1224fcf5ef2aSThomas Huth 1225f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1226f91c60f0SEdgar E. Iglesias { 1227f91c60f0SEdgar E. Iglesias TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)); 1228f91c60f0SEdgar E. Iglesias 1229f91c60f0SEdgar E. Iglesias dc->delayed_branch = 2; 1230f91c60f0SEdgar E. Iglesias dc->tb_flags |= D_FLAG; 1231f91c60f0SEdgar E. Iglesias 1232f91c60f0SEdgar E. Iglesias tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm)); 1233f91c60f0SEdgar E. Iglesias tcg_temp_free_i32(tmp); 1234f91c60f0SEdgar E. Iglesias } 1235f91c60f0SEdgar E. Iglesias 1236fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc) 1237fcf5ef2aSThomas Huth { 1238fcf5ef2aSThomas Huth unsigned int cc; 1239fcf5ef2aSThomas Huth unsigned int dslot; 1240fcf5ef2aSThomas Huth 1241fcf5ef2aSThomas Huth cc = EXTRACT_FIELD(dc->ir, 21, 23); 1242fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 25); 1243fcf5ef2aSThomas Huth 1244fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1245fcf5ef2aSThomas Huth if (dslot) { 1246f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1247fcf5ef2aSThomas Huth } 1248fcf5ef2aSThomas Huth 1249d7ecb757SRichard Henderson if (dc->type_b) { 1250fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT_CC; 1251d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1252d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1253fcf5ef2aSThomas Huth } else { 1254fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 1255d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1256fcf5ef2aSThomas Huth } 12579b158558SRichard Henderson eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); 1258fcf5ef2aSThomas Huth } 1259fcf5ef2aSThomas Huth 1260fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc) 1261fcf5ef2aSThomas Huth { 1262fcf5ef2aSThomas Huth unsigned int dslot, link, abs, mbar; 1263fcf5ef2aSThomas Huth 1264fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 20); 1265fcf5ef2aSThomas Huth abs = dc->ir & (1 << 19); 1266fcf5ef2aSThomas Huth link = dc->ir & (1 << 18); 1267fcf5ef2aSThomas Huth 1268fcf5ef2aSThomas Huth /* Memory barrier. */ 1269fcf5ef2aSThomas Huth mbar = (dc->ir >> 16) & 31; 1270fcf5ef2aSThomas Huth if (mbar == 2 && dc->imm == 4) { 1271badcbf9dSEdgar E. Iglesias uint16_t mbar_imm = dc->rd; 1272badcbf9dSEdgar E. Iglesias 12733f172744SEdgar E. Iglesias /* Data access memory barrier. */ 12743f172744SEdgar E. Iglesias if ((mbar_imm & 2) == 0) { 12753f172744SEdgar E. Iglesias tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 12763f172744SEdgar E. Iglesias } 12773f172744SEdgar E. Iglesias 1278fcf5ef2aSThomas Huth /* mbar IMM & 16 decodes to sleep. */ 1279badcbf9dSEdgar E. Iglesias if (mbar_imm & 16) { 128041ba37c4SRichard Henderson TCGv_i32 tmp_1; 1281fcf5ef2aSThomas Huth 1282b4919e7dSEdgar E. Iglesias if (trap_userspace(dc, true)) { 1283b4919e7dSEdgar E. Iglesias /* Sleep is a privileged instruction. */ 1284b4919e7dSEdgar E. Iglesias return; 1285b4919e7dSEdgar E. Iglesias } 1286b4919e7dSEdgar E. Iglesias 1287fcf5ef2aSThomas Huth t_sync_flags(dc); 128841ba37c4SRichard Henderson 128941ba37c4SRichard Henderson tmp_1 = tcg_const_i32(1); 1290fcf5ef2aSThomas Huth tcg_gen_st_i32(tmp_1, cpu_env, 1291fcf5ef2aSThomas Huth -offsetof(MicroBlazeCPU, env) 1292fcf5ef2aSThomas Huth +offsetof(CPUState, halted)); 1293fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp_1); 129441ba37c4SRichard Henderson 1295d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 129641ba37c4SRichard Henderson 129741ba37c4SRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1298fcf5ef2aSThomas Huth return; 1299fcf5ef2aSThomas Huth } 1300fcf5ef2aSThomas Huth /* Break the TB. */ 1301fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 1302fcf5ef2aSThomas Huth return; 1303fcf5ef2aSThomas Huth } 1304fcf5ef2aSThomas Huth 1305d7ecb757SRichard Henderson if (abs && link && !dslot) { 1306d7ecb757SRichard Henderson if (dc->type_b) { 1307d7ecb757SRichard Henderson /* BRKI */ 1308d7ecb757SRichard Henderson uint32_t imm = dec_alu_typeb_imm(dc); 1309d7ecb757SRichard Henderson if (trap_userspace(dc, imm != 8 && imm != 0x18)) { 1310d7ecb757SRichard Henderson return; 1311d7ecb757SRichard Henderson } 1312d7ecb757SRichard Henderson } else { 1313d7ecb757SRichard Henderson /* BRK */ 1314d7ecb757SRichard Henderson if (trap_userspace(dc, true)) { 1315d7ecb757SRichard Henderson return; 1316d7ecb757SRichard Henderson } 1317d7ecb757SRichard Henderson } 1318d7ecb757SRichard Henderson } 1319d7ecb757SRichard Henderson 1320fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1321fcf5ef2aSThomas Huth if (dslot) { 1322f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1323fcf5ef2aSThomas Huth } 1324d7ecb757SRichard Henderson if (link && dc->rd) { 1325d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1326d7ecb757SRichard Henderson } 1327fcf5ef2aSThomas Huth 1328fcf5ef2aSThomas Huth if (abs) { 1329d7ecb757SRichard Henderson if (dc->type_b) { 1330d7ecb757SRichard Henderson uint32_t dest = dec_alu_typeb_imm(dc); 1331d7ecb757SRichard Henderson 1332d7ecb757SRichard Henderson dc->jmp = JMP_DIRECT; 1333d7ecb757SRichard Henderson dc->jmp_pc = dest; 1334d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dest); 1335fcf5ef2aSThomas Huth if (link && !dslot) { 1336d7ecb757SRichard Henderson switch (dest) { 1337d7ecb757SRichard Henderson case 8: 1338d7ecb757SRichard Henderson case 0x18: 1339d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 1340d7ecb757SRichard Henderson break; 1341d7ecb757SRichard Henderson case 0: 1342d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1343d7ecb757SRichard Henderson break; 1344d7ecb757SRichard Henderson } 1345d7ecb757SRichard Henderson } 1346d7ecb757SRichard Henderson } else { 1347d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1348d7ecb757SRichard Henderson tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]); 1349d7ecb757SRichard Henderson if (link && !dslot) { 135041ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 135141ba37c4SRichard Henderson } 1352fcf5ef2aSThomas Huth } 1353d7ecb757SRichard Henderson } else if (dc->type_b) { 1354fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT; 1355d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1356d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1357fcf5ef2aSThomas Huth } else { 1358d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1359d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1360d7ecb757SRichard Henderson } 13619b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 1362fcf5ef2aSThomas Huth } 1363fcf5ef2aSThomas Huth 1364fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc) 1365fcf5ef2aSThomas Huth { 1366cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1367cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1368cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13693e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13700a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 13710a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1372cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1373fcf5ef2aSThomas Huth 1374cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1375cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1376fcf5ef2aSThomas Huth msr_write(dc, t1); 1377cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1378cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1379fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1380fcf5ef2aSThomas Huth } 1381fcf5ef2aSThomas Huth 1382fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc) 1383fcf5ef2aSThomas Huth { 1384cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1385cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1386cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13873e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13880a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1389cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1390cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1391fcf5ef2aSThomas Huth 1392cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1393cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1394fcf5ef2aSThomas Huth msr_write(dc, t1); 1395cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1396cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1397fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1398fcf5ef2aSThomas Huth } 1399fcf5ef2aSThomas Huth 1400fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc) 1401fcf5ef2aSThomas Huth { 1402cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1403cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1404cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1405fcf5ef2aSThomas Huth 14063e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 14070a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1408cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1409cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1410cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1411fcf5ef2aSThomas Huth 1412cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1413cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1414fcf5ef2aSThomas Huth msr_write(dc, t1); 1415cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1416cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1417fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1418fcf5ef2aSThomas Huth } 1419fcf5ef2aSThomas Huth 1420fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc) 1421fcf5ef2aSThomas Huth { 1422fcf5ef2aSThomas Huth unsigned int b_bit, i_bit, e_bit; 1423fcf5ef2aSThomas Huth 1424fcf5ef2aSThomas Huth i_bit = dc->ir & (1 << 21); 1425fcf5ef2aSThomas Huth b_bit = dc->ir & (1 << 22); 1426fcf5ef2aSThomas Huth e_bit = dc->ir & (1 << 23); 1427fcf5ef2aSThomas Huth 1428bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1429bdfc1e88SEdgar E. Iglesias return; 1430bdfc1e88SEdgar E. Iglesias } 1431bdfc1e88SEdgar E. Iglesias 1432f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1433fcf5ef2aSThomas Huth 1434fcf5ef2aSThomas Huth if (i_bit) { 1435fcf5ef2aSThomas Huth dc->tb_flags |= DRTI_FLAG; 1436fcf5ef2aSThomas Huth } else if (b_bit) { 1437fcf5ef2aSThomas Huth dc->tb_flags |= DRTB_FLAG; 1438fcf5ef2aSThomas Huth } else if (e_bit) { 1439fcf5ef2aSThomas Huth dc->tb_flags |= DRTE_FLAG; 144011105d67SRichard Henderson } 1441fcf5ef2aSThomas Huth 1442fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 14439b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 14440f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 1445fcf5ef2aSThomas Huth } 1446fcf5ef2aSThomas Huth 1447fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc) 1448fcf5ef2aSThomas Huth { 14499ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 1450fcf5ef2aSThomas Huth return; 1451fcf5ef2aSThomas Huth } 1452d4705ae0SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", 1453d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, dc->opcode); 1454fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1455fcf5ef2aSThomas Huth } 1456fcf5ef2aSThomas Huth 1457fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 1458fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc) 1459fcf5ef2aSThomas Huth { 1460fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1461fcf5ef2aSThomas Huth int ctrl; 1462fcf5ef2aSThomas Huth 1463bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 1464fcf5ef2aSThomas Huth return; 1465fcf5ef2aSThomas Huth } 1466fcf5ef2aSThomas Huth 1467cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 1468fcf5ef2aSThomas Huth if (dc->type_b) { 1469cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 1470fcf5ef2aSThomas Huth ctrl = dc->imm >> 10; 1471fcf5ef2aSThomas Huth } else { 1472cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 1473fcf5ef2aSThomas Huth ctrl = dc->imm >> 5; 1474fcf5ef2aSThomas Huth } 1475fcf5ef2aSThomas Huth 1476cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 1477fcf5ef2aSThomas Huth 1478fcf5ef2aSThomas Huth if (dc->rd == 0) { 1479fcf5ef2aSThomas Huth gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 1480fcf5ef2aSThomas Huth } else { 1481fcf5ef2aSThomas Huth gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 1482fcf5ef2aSThomas Huth } 1483cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1484cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 1485fcf5ef2aSThomas Huth } 1486fcf5ef2aSThomas Huth 1487fcf5ef2aSThomas Huth static struct decoder_info { 1488fcf5ef2aSThomas Huth struct { 1489fcf5ef2aSThomas Huth uint32_t bits; 1490fcf5ef2aSThomas Huth uint32_t mask; 1491fcf5ef2aSThomas Huth }; 1492fcf5ef2aSThomas Huth void (*dec)(DisasContext *dc); 1493fcf5ef2aSThomas Huth } decinfo[] = { 1494fcf5ef2aSThomas Huth {DEC_LD, dec_load}, 1495fcf5ef2aSThomas Huth {DEC_ST, dec_store}, 1496fcf5ef2aSThomas Huth {DEC_BR, dec_br}, 1497fcf5ef2aSThomas Huth {DEC_BCC, dec_bcc}, 1498fcf5ef2aSThomas Huth {DEC_RTS, dec_rts}, 1499fcf5ef2aSThomas Huth {DEC_MSR, dec_msr}, 1500fcf5ef2aSThomas Huth {DEC_STREAM, dec_stream}, 1501fcf5ef2aSThomas Huth {{0, 0}, dec_null} 1502fcf5ef2aSThomas Huth }; 1503fcf5ef2aSThomas Huth 150444d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir) 1505fcf5ef2aSThomas Huth { 1506fcf5ef2aSThomas Huth int i; 1507fcf5ef2aSThomas Huth 1508fcf5ef2aSThomas Huth dc->ir = ir; 1509fcf5ef2aSThomas Huth 1510fcf5ef2aSThomas Huth /* bit 2 seems to indicate insn type. */ 1511fcf5ef2aSThomas Huth dc->type_b = ir & (1 << 29); 1512fcf5ef2aSThomas Huth 1513fcf5ef2aSThomas Huth dc->opcode = EXTRACT_FIELD(ir, 26, 31); 1514fcf5ef2aSThomas Huth dc->rd = EXTRACT_FIELD(ir, 21, 25); 1515fcf5ef2aSThomas Huth dc->ra = EXTRACT_FIELD(ir, 16, 20); 1516fcf5ef2aSThomas Huth dc->rb = EXTRACT_FIELD(ir, 11, 15); 1517fcf5ef2aSThomas Huth dc->imm = EXTRACT_FIELD(ir, 0, 15); 1518fcf5ef2aSThomas Huth 1519fcf5ef2aSThomas Huth /* Large switch for all insns. */ 1520fcf5ef2aSThomas Huth for (i = 0; i < ARRAY_SIZE(decinfo); i++) { 1521fcf5ef2aSThomas Huth if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { 1522fcf5ef2aSThomas Huth decinfo[i].dec(dc); 1523fcf5ef2aSThomas Huth break; 1524fcf5ef2aSThomas Huth } 1525fcf5ef2aSThomas Huth } 1526fcf5ef2aSThomas Huth } 1527fcf5ef2aSThomas Huth 1528372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1529fcf5ef2aSThomas Huth { 1530372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1531372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1532372122e3SRichard Henderson int bound; 1533fcf5ef2aSThomas Huth 1534fcf5ef2aSThomas Huth dc->cpu = cpu; 1535372122e3SRichard Henderson dc->synced_flags = dc->tb_flags = dc->base.tb->flags; 1536fcf5ef2aSThomas Huth dc->delayed_branch = !!(dc->tb_flags & D_FLAG); 1537372122e3SRichard Henderson dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; 1538fcf5ef2aSThomas Huth dc->cpustate_changed = 0; 1539fcf5ef2aSThomas Huth dc->abort_at_next_insn = 0; 1540d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 154120800179SRichard Henderson dc->r0 = NULL; 154220800179SRichard Henderson dc->r0_set = false; 1543fcf5ef2aSThomas Huth 1544372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1545372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1546fcf5ef2aSThomas Huth } 1547fcf5ef2aSThomas Huth 1548372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1549fcf5ef2aSThomas Huth { 1550fcf5ef2aSThomas Huth } 1551fcf5ef2aSThomas Huth 1552372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1553372122e3SRichard Henderson { 1554372122e3SRichard Henderson tcg_gen_insn_start(dcb->pc_next); 1555372122e3SRichard Henderson } 1556fcf5ef2aSThomas Huth 1557372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1558372122e3SRichard Henderson const CPUBreakpoint *bp) 1559372122e3SRichard Henderson { 1560372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1561372122e3SRichard Henderson 1562372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1563372122e3SRichard Henderson 1564372122e3SRichard Henderson /* 1565372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1566372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1567372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1568372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1569372122e3SRichard Henderson */ 1570372122e3SRichard Henderson dc->base.pc_next += 4; 1571372122e3SRichard Henderson return true; 1572372122e3SRichard Henderson } 1573372122e3SRichard Henderson 1574372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1575372122e3SRichard Henderson { 1576372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1577372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 157844d1432bSRichard Henderson uint32_t ir; 1579372122e3SRichard Henderson 1580372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1581372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1582372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1583372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1584fcf5ef2aSThomas Huth } 1585fcf5ef2aSThomas Huth 1586fcf5ef2aSThomas Huth dc->clear_imm = 1; 158744d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 158844d1432bSRichard Henderson if (!decode(dc, ir)) { 158944d1432bSRichard Henderson old_decode(dc, ir); 159044d1432bSRichard Henderson } 159120800179SRichard Henderson 159220800179SRichard Henderson if (dc->r0) { 159320800179SRichard Henderson tcg_temp_free_i32(dc->r0); 159420800179SRichard Henderson dc->r0 = NULL; 159520800179SRichard Henderson dc->r0_set = false; 159620800179SRichard Henderson } 159720800179SRichard Henderson 1598d7ecb757SRichard Henderson if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { 1599fcf5ef2aSThomas Huth dc->tb_flags &= ~IMM_FLAG; 1600d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1601372122e3SRichard Henderson } 1602d4705ae0SRichard Henderson dc->base.pc_next += 4; 1603fcf5ef2aSThomas Huth 1604372122e3SRichard Henderson if (dc->delayed_branch && --dc->delayed_branch == 0) { 1605372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 1606fcf5ef2aSThomas Huth do_rti(dc); 1607372122e3SRichard Henderson } 1608372122e3SRichard Henderson if (dc->tb_flags & DRTB_FLAG) { 1609fcf5ef2aSThomas Huth do_rtb(dc); 1610372122e3SRichard Henderson } 1611372122e3SRichard Henderson if (dc->tb_flags & DRTE_FLAG) { 1612fcf5ef2aSThomas Huth do_rte(dc); 1613372122e3SRichard Henderson } 1614fcf5ef2aSThomas Huth /* Clear the delay slot flag. */ 1615fcf5ef2aSThomas Huth dc->tb_flags &= ~D_FLAG; 1616372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1617372122e3SRichard Henderson } 1618372122e3SRichard Henderson 1619372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1620372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1621372122e3SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1622372122e3SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1623372122e3SRichard Henderson } 1624372122e3SRichard Henderson } 1625372122e3SRichard Henderson 1626372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1627372122e3SRichard Henderson { 1628372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1629372122e3SRichard Henderson 1630372122e3SRichard Henderson assert(!dc->abort_at_next_insn); 1631372122e3SRichard Henderson 1632372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1633372122e3SRichard Henderson /* We have already exited the TB. */ 1634372122e3SRichard Henderson return; 1635372122e3SRichard Henderson } 1636372122e3SRichard Henderson 1637372122e3SRichard Henderson t_sync_flags(dc); 1638372122e3SRichard Henderson if (dc->tb_flags & D_FLAG) { 1639372122e3SRichard Henderson sync_jmpstate(dc); 1640372122e3SRichard Henderson dc->jmp = JMP_NOJMP; 1641372122e3SRichard Henderson } 1642372122e3SRichard Henderson 1643372122e3SRichard Henderson switch (dc->base.is_jmp) { 1644372122e3SRichard Henderson case DISAS_TOO_MANY: 1645372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1646372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1647372122e3SRichard Henderson return; 1648372122e3SRichard Henderson 1649372122e3SRichard Henderson case DISAS_UPDATE: 1650372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1651372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1652372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1653372122e3SRichard Henderson } else { 1654372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1655372122e3SRichard Henderson } 1656372122e3SRichard Henderson return; 1657372122e3SRichard Henderson 1658372122e3SRichard Henderson case DISAS_JUMP: 1659372122e3SRichard Henderson switch (dc->jmp) { 1660372122e3SRichard Henderson case JMP_INDIRECT: 1661372122e3SRichard Henderson { 1662d4705ae0SRichard Henderson TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); 16630f96e96bSRichard Henderson eval_cond_jmp(dc, cpu_btarget, tmp_pc); 16640f96e96bSRichard Henderson tcg_temp_free_i32(tmp_pc); 1665372122e3SRichard Henderson 1666372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1667372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1668372122e3SRichard Henderson } else { 1669372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1670372122e3SRichard Henderson } 1671372122e3SRichard Henderson } 1672372122e3SRichard Henderson return; 1673372122e3SRichard Henderson 1674372122e3SRichard Henderson case JMP_DIRECT_CC: 1675372122e3SRichard Henderson { 1676fcf5ef2aSThomas Huth TCGLabel *l1 = gen_new_label(); 16779b158558SRichard Henderson tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); 1678d4705ae0SRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1679fcf5ef2aSThomas Huth gen_set_label(l1); 1680372122e3SRichard Henderson } 1681372122e3SRichard Henderson /* fall through */ 1682372122e3SRichard Henderson 1683372122e3SRichard Henderson case JMP_DIRECT: 1684fcf5ef2aSThomas Huth gen_goto_tb(dc, 0, dc->jmp_pc); 1685372122e3SRichard Henderson return; 1686fcf5ef2aSThomas Huth } 1687372122e3SRichard Henderson /* fall through */ 1688fcf5ef2aSThomas Huth 1689a2b80dbdSRichard Henderson default: 1690a2b80dbdSRichard Henderson g_assert_not_reached(); 1691fcf5ef2aSThomas Huth } 1692fcf5ef2aSThomas Huth } 1693fcf5ef2aSThomas Huth 1694372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1695372122e3SRichard Henderson { 1696372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1697372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 1698fcf5ef2aSThomas Huth } 1699372122e3SRichard Henderson 1700372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1701372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1702372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1703372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1704372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1705372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1706372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1707372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1708372122e3SRichard Henderson }; 1709372122e3SRichard Henderson 1710372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1711372122e3SRichard Henderson { 1712372122e3SRichard Henderson DisasContext dc; 1713372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 1714fcf5ef2aSThomas Huth } 1715fcf5ef2aSThomas Huth 171690c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1717fcf5ef2aSThomas Huth { 1718fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1719fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 1720fcf5ef2aSThomas Huth int i; 1721fcf5ef2aSThomas Huth 172290c84c56SMarkus Armbruster if (!env) { 1723fcf5ef2aSThomas Huth return; 172490c84c56SMarkus Armbruster } 1725fcf5ef2aSThomas Huth 17260f96e96bSRichard Henderson qemu_fprintf(f, "IN: PC=%x %s\n", 172776e8187dSRichard Henderson env->pc, lookup_symbol(env->pc)); 17286efd5599SRichard Henderson qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " 1729eb2022b7SRichard Henderson "imm=%x iflags=%x fsr=%x rbtr=%x\n", 173078e9caf2SRichard Henderson env->msr, env->esr, env->ear, 1731eb2022b7SRichard Henderson env->imm, env->iflags, env->fsr, env->btr); 17320f96e96bSRichard Henderson qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 1733fcf5ef2aSThomas Huth env->btaken, env->btarget, 17342e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 17352e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 17362e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 17372e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 17382ead1b18SJoe Komlodi for (i = 0; i < 12; i++) { 17392ead1b18SJoe Komlodi qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); 17402ead1b18SJoe Komlodi if ((i + 1) % 4 == 0) { 17412ead1b18SJoe Komlodi qemu_fprintf(f, "\n"); 17422ead1b18SJoe Komlodi } 17432ead1b18SJoe Komlodi } 1744fcf5ef2aSThomas Huth 17452ead1b18SJoe Komlodi /* Registers that aren't modeled are reported as 0 */ 174639db007eSRichard Henderson qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " 1747af20a93aSRichard Henderson "rtlblo=0 rtlbhi=0\n", env->edr); 17482ead1b18SJoe Komlodi qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); 1749fcf5ef2aSThomas Huth for (i = 0; i < 32; i++) { 175090c84c56SMarkus Armbruster qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); 1751fcf5ef2aSThomas Huth if ((i + 1) % 4 == 0) 175290c84c56SMarkus Armbruster qemu_fprintf(f, "\n"); 1753fcf5ef2aSThomas Huth } 175490c84c56SMarkus Armbruster qemu_fprintf(f, "\n\n"); 1755fcf5ef2aSThomas Huth } 1756fcf5ef2aSThomas Huth 1757fcf5ef2aSThomas Huth void mb_tcg_init(void) 1758fcf5ef2aSThomas Huth { 1759480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1760480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1761fcf5ef2aSThomas Huth 1762480d29a8SRichard Henderson static const struct { 1763480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1764480d29a8SRichard Henderson } i32s[] = { 1765480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1766480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1767480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1768480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1769480d29a8SRichard Henderson 1770480d29a8SRichard Henderson SP(pc), 1771480d29a8SRichard Henderson SP(msr), 17721074c0fbSRichard Henderson SP(msr_c), 1773480d29a8SRichard Henderson SP(imm), 1774480d29a8SRichard Henderson SP(iflags), 1775480d29a8SRichard Henderson SP(btaken), 1776480d29a8SRichard Henderson SP(btarget), 1777480d29a8SRichard Henderson SP(res_val), 1778480d29a8SRichard Henderson }; 1779480d29a8SRichard Henderson 1780480d29a8SRichard Henderson #undef R 1781480d29a8SRichard Henderson #undef SP 1782480d29a8SRichard Henderson 1783480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1784480d29a8SRichard Henderson *i32s[i].var = 1785480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1786fcf5ef2aSThomas Huth } 178776e8187dSRichard Henderson 1788480d29a8SRichard Henderson cpu_res_addr = 1789480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1790fcf5ef2aSThomas Huth } 1791fcf5ef2aSThomas Huth 1792fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1793fcf5ef2aSThomas Huth target_ulong *data) 1794fcf5ef2aSThomas Huth { 179576e8187dSRichard Henderson env->pc = data[0]; 1796fcf5ef2aSThomas Huth } 1797