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 24420800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 24520800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 24620800179SRichard Henderson { 24720800179SRichard Henderson TCGv_i32 rd, ra; 24820800179SRichard Henderson 24920800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 25020800179SRichard Henderson return true; 25120800179SRichard Henderson } 25220800179SRichard Henderson 25320800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 25420800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 25520800179SRichard Henderson fni(rd, ra, arg->imm); 25620800179SRichard Henderson return true; 25720800179SRichard Henderson } 25820800179SRichard Henderson 25920800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 26020800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 26120800179SRichard Henderson { 26220800179SRichard Henderson TCGv_i32 rd, ra, imm; 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 imm = tcg_const_i32(arg->imm); 27120800179SRichard Henderson 27220800179SRichard Henderson fn(rd, ra, imm); 27320800179SRichard Henderson 27420800179SRichard Henderson tcg_temp_free_i32(imm); 27520800179SRichard Henderson return true; 27620800179SRichard Henderson } 27720800179SRichard Henderson 27820800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 27920800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 28020800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 28120800179SRichard Henderson 282607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 283607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 284607f5767SRichard Henderson { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } 285607f5767SRichard Henderson 28620800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 28720800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 28820800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 28920800179SRichard Henderson 290*97955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 291*97955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 292*97955cebSRichard Henderson { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } 293*97955cebSRichard Henderson 29420800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 29520800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 29620800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 29720800179SRichard Henderson 29820800179SRichard Henderson /* No input carry, but output carry. */ 29920800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 30020800179SRichard Henderson { 30120800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 30220800179SRichard Henderson 30320800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 30420800179SRichard Henderson 30520800179SRichard Henderson tcg_temp_free_i32(zero); 30620800179SRichard Henderson } 30720800179SRichard Henderson 30820800179SRichard Henderson /* Input and output carry. */ 30920800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 31020800179SRichard Henderson { 31120800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 31220800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 31320800179SRichard Henderson 31420800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 31520800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 31620800179SRichard Henderson 31720800179SRichard Henderson tcg_temp_free_i32(tmp); 31820800179SRichard Henderson tcg_temp_free_i32(zero); 31920800179SRichard Henderson } 32020800179SRichard Henderson 32120800179SRichard Henderson /* Input carry, but no output carry. */ 32220800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 32320800179SRichard Henderson { 32420800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 32520800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 32620800179SRichard Henderson } 32720800179SRichard Henderson 32820800179SRichard Henderson DO_TYPEA(add, true, gen_add) 32920800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 33020800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 33120800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 33220800179SRichard Henderson 33320800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 33420800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 33520800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 33620800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 33720800179SRichard Henderson 338cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 339cb0a0a4cSRichard Henderson { 340cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 341cb0a0a4cSRichard Henderson } 342cb0a0a4cSRichard Henderson 343cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 344cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 345cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 346cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 347cb0a0a4cSRichard Henderson 34858b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 34958b48b63SRichard Henderson { 35058b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 35158b48b63SRichard Henderson 35258b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 35358b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 35458b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 35558b48b63SRichard Henderson tcg_temp_free_i32(lt); 35658b48b63SRichard Henderson } 35758b48b63SRichard Henderson 35858b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 35958b48b63SRichard Henderson { 36058b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 36158b48b63SRichard Henderson 36258b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 36358b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 36458b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 36558b48b63SRichard Henderson tcg_temp_free_i32(lt); 36658b48b63SRichard Henderson } 36758b48b63SRichard Henderson 36858b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 36958b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 370a2b0b90eSRichard Henderson 371*97955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 372*97955cebSRichard Henderson { 373*97955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 374*97955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 375*97955cebSRichard Henderson tcg_temp_free_i32(tmp); 376*97955cebSRichard Henderson } 377*97955cebSRichard Henderson 378*97955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 379*97955cebSRichard Henderson { 380*97955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 381*97955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 382*97955cebSRichard Henderson tcg_temp_free_i32(tmp); 383*97955cebSRichard Henderson } 384*97955cebSRichard Henderson 385*97955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 386*97955cebSRichard Henderson { 387*97955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 388*97955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 389*97955cebSRichard Henderson tcg_temp_free_i32(tmp); 390*97955cebSRichard Henderson } 391*97955cebSRichard Henderson 392*97955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 393*97955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 394*97955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 395*97955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 396*97955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 397*97955cebSRichard Henderson 398cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 399cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 400cb0a0a4cSRichard Henderson 401607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 402607f5767SRichard Henderson { 403607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 404607f5767SRichard Henderson } 405607f5767SRichard Henderson 406607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 407607f5767SRichard Henderson { 408607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 409607f5767SRichard Henderson } 410607f5767SRichard Henderson 411607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 412607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 413607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 414607f5767SRichard Henderson 415a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 416a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 417a2b0b90eSRichard Henderson { 418a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 419a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 420a2b0b90eSRichard Henderson } 421a2b0b90eSRichard Henderson 422a2b0b90eSRichard Henderson /* Input and output carry. */ 423a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 424a2b0b90eSRichard Henderson { 425a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 426a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 427a2b0b90eSRichard Henderson 428a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 429a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 430a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 431a2b0b90eSRichard Henderson 432a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 433a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 434a2b0b90eSRichard Henderson } 435a2b0b90eSRichard Henderson 436a2b0b90eSRichard Henderson /* No input or output carry. */ 437a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 438a2b0b90eSRichard Henderson { 439a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 440a2b0b90eSRichard Henderson } 441a2b0b90eSRichard Henderson 442a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 443a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 444a2b0b90eSRichard Henderson { 445a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 446a2b0b90eSRichard Henderson 447a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 448a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 449a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 450a2b0b90eSRichard Henderson 451a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 452a2b0b90eSRichard Henderson } 453a2b0b90eSRichard Henderson 454a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 455a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 456a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 457a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 458a2b0b90eSRichard Henderson 459a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 460a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 461a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 462a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 463a2b0b90eSRichard Henderson 464cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 465cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 466cb0a0a4cSRichard Henderson 46720800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 46820800179SRichard Henderson { 46920800179SRichard Henderson /* If opcode_0_illegal, trap. */ 47020800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 47120800179SRichard Henderson trap_illegal(dc, true); 47220800179SRichard Henderson return true; 47320800179SRichard Henderson } 47420800179SRichard Henderson /* 47520800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 47620800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 47720800179SRichard Henderson */ 47820800179SRichard Henderson return false; 479fcf5ef2aSThomas Huth } 480fcf5ef2aSThomas Huth 4811074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 482fcf5ef2aSThomas Huth { 4831074c0fbSRichard Henderson TCGv_i32 t; 4841074c0fbSRichard Henderson 4851074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 4861074c0fbSRichard Henderson t = tcg_temp_new_i32(); 4871074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 4881074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 4891074c0fbSRichard Henderson tcg_temp_free_i32(t); 490fcf5ef2aSThomas Huth } 491fcf5ef2aSThomas Huth 4921074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 493fcf5ef2aSThomas Huth { 494fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 4951074c0fbSRichard Henderson 4961074c0fbSRichard Henderson /* Install MSR_C. */ 4971074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 4981074c0fbSRichard Henderson 4991074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 5001074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 501fcf5ef2aSThomas Huth } 502fcf5ef2aSThomas Huth 503fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc) 504fcf5ef2aSThomas Huth { 505fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 506cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 5072023e9a3SEdgar E. Iglesias unsigned int sr, rn; 508f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 509fcf5ef2aSThomas Huth 5102023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 5112023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 5122023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 513fcf5ef2aSThomas Huth dc->type_b = 1; 5142023e9a3SEdgar E. Iglesias if (to) { 515fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 516f0f7e7f7SEdgar E. Iglesias } 517f0f7e7f7SEdgar E. Iglesias 518f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 519f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 520f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 521f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 522f0f7e7f7SEdgar E. Iglesias 523f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 5242023e9a3SEdgar E. Iglesias } 525fcf5ef2aSThomas Huth 526fcf5ef2aSThomas Huth /* msrclr and msrset. */ 5272023e9a3SEdgar E. Iglesias if (clrset) { 5282023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 529fcf5ef2aSThomas Huth 53056837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 531fcf5ef2aSThomas Huth /* nop??? */ 532fcf5ef2aSThomas Huth return; 533fcf5ef2aSThomas Huth } 534fcf5ef2aSThomas Huth 535bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 536fcf5ef2aSThomas Huth return; 537fcf5ef2aSThomas Huth } 538fcf5ef2aSThomas Huth 539fcf5ef2aSThomas Huth if (dc->rd) 540fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 541fcf5ef2aSThomas Huth 542cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 543cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 544fcf5ef2aSThomas Huth msr_read(dc, t0); 545cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 546fcf5ef2aSThomas Huth 547fcf5ef2aSThomas Huth if (clr) { 548cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 549cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 550fcf5ef2aSThomas Huth } else 551cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 552fcf5ef2aSThomas Huth msr_write(dc, t0); 553cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 554cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 555d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 556d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 557fcf5ef2aSThomas Huth return; 558fcf5ef2aSThomas Huth } 559fcf5ef2aSThomas Huth 560bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 561fcf5ef2aSThomas Huth return; 562fcf5ef2aSThomas Huth } 563fcf5ef2aSThomas Huth 564fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 565fcf5ef2aSThomas Huth /* Catch read/writes to the mmu block. */ 566fcf5ef2aSThomas Huth if ((sr & ~0xff) == 0x1000) { 567f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 56805a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 56905a9a651SEdgar E. Iglesias 570fcf5ef2aSThomas Huth sr &= 7; 57105a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 57205a9a651SEdgar E. Iglesias if (to) { 573f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 57405a9a651SEdgar E. Iglesias } else { 575f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 57605a9a651SEdgar E. Iglesias } 57705a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 578f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 579fcf5ef2aSThomas Huth return; 580fcf5ef2aSThomas Huth } 581fcf5ef2aSThomas Huth #endif 582fcf5ef2aSThomas Huth 583fcf5ef2aSThomas Huth if (to) { 584fcf5ef2aSThomas Huth switch (sr) { 585aa28e6d4SRichard Henderson case SR_PC: 586fcf5ef2aSThomas Huth break; 587aa28e6d4SRichard Henderson case SR_MSR: 588fcf5ef2aSThomas Huth msr_write(dc, cpu_R[dc->ra]); 589fcf5ef2aSThomas Huth break; 590351527b7SEdgar E. Iglesias case SR_EAR: 591dbdb77c4SRichard Henderson { 592dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 593dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 594dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 595dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 596dbdb77c4SRichard Henderson } 597aa28e6d4SRichard Henderson break; 598351527b7SEdgar E. Iglesias case SR_ESR: 59941ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 60041ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 601aa28e6d4SRichard Henderson break; 602ab6dd380SEdgar E. Iglesias case SR_FSR: 60386017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 60486017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 605aa28e6d4SRichard Henderson break; 606aa28e6d4SRichard Henderson case SR_BTR: 607ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 608ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 609aa28e6d4SRichard Henderson break; 610aa28e6d4SRichard Henderson case SR_EDR: 61139db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 61239db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 613fcf5ef2aSThomas Huth break; 614fcf5ef2aSThomas Huth case 0x800: 615cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 616cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 617fcf5ef2aSThomas Huth break; 618fcf5ef2aSThomas Huth case 0x802: 619cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 620cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 621fcf5ef2aSThomas Huth break; 622fcf5ef2aSThomas Huth default: 623fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 624fcf5ef2aSThomas Huth break; 625fcf5ef2aSThomas Huth } 626fcf5ef2aSThomas Huth } else { 627fcf5ef2aSThomas Huth switch (sr) { 628aa28e6d4SRichard Henderson case SR_PC: 629d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 630fcf5ef2aSThomas Huth break; 631aa28e6d4SRichard Henderson case SR_MSR: 632fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 633fcf5ef2aSThomas Huth break; 634351527b7SEdgar E. Iglesias case SR_EAR: 635dbdb77c4SRichard Henderson { 636dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 637dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 638a1b48e3aSEdgar E. Iglesias if (extended) { 639dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 640aa28e6d4SRichard Henderson } else { 641dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 642dbdb77c4SRichard Henderson } 643dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 644a1b48e3aSEdgar E. Iglesias } 645aa28e6d4SRichard Henderson break; 646351527b7SEdgar E. Iglesias case SR_ESR: 64741ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 64841ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 649aa28e6d4SRichard Henderson break; 650351527b7SEdgar E. Iglesias case SR_FSR: 65186017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 65286017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 653aa28e6d4SRichard Henderson break; 654351527b7SEdgar E. Iglesias case SR_BTR: 655ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 656ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 657aa28e6d4SRichard Henderson break; 6587cdae31dSTong Ho case SR_EDR: 65939db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 66039db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 661fcf5ef2aSThomas Huth break; 662fcf5ef2aSThomas Huth case 0x800: 663cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 664cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 665fcf5ef2aSThomas Huth break; 666fcf5ef2aSThomas Huth case 0x802: 667cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 668cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 669fcf5ef2aSThomas Huth break; 670351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 671fcf5ef2aSThomas Huth rn = sr & 0xf; 672cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 673fcf5ef2aSThomas Huth cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 674fcf5ef2aSThomas Huth break; 675fcf5ef2aSThomas Huth default: 676fcf5ef2aSThomas Huth cpu_abort(cs, "unknown mfs reg %x\n", sr); 677fcf5ef2aSThomas Huth break; 678fcf5ef2aSThomas Huth } 679fcf5ef2aSThomas Huth } 680fcf5ef2aSThomas Huth 681fcf5ef2aSThomas Huth if (dc->rd == 0) { 682cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 683fcf5ef2aSThomas Huth } 684fcf5ef2aSThomas Huth } 685fcf5ef2aSThomas Huth 686fcf5ef2aSThomas Huth /* Div unit. */ 687fcf5ef2aSThomas Huth static void dec_div(DisasContext *dc) 688fcf5ef2aSThomas Huth { 689fcf5ef2aSThomas Huth unsigned int u; 690fcf5ef2aSThomas Huth 691fcf5ef2aSThomas Huth u = dc->imm & 2; 692fcf5ef2aSThomas Huth 6939ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_div)) { 6949ba8cd45SEdgar E. Iglesias return; 695fcf5ef2aSThomas Huth } 696fcf5ef2aSThomas Huth 697fcf5ef2aSThomas Huth if (u) 698fcf5ef2aSThomas Huth gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), 699fcf5ef2aSThomas Huth cpu_R[dc->ra]); 700fcf5ef2aSThomas Huth else 701fcf5ef2aSThomas Huth gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), 702fcf5ef2aSThomas Huth cpu_R[dc->ra]); 703fcf5ef2aSThomas Huth if (!dc->rd) 704cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[dc->rd], 0); 705fcf5ef2aSThomas Huth } 706fcf5ef2aSThomas Huth 707fcf5ef2aSThomas Huth static void dec_barrel(DisasContext *dc) 708fcf5ef2aSThomas Huth { 709cfeea807SEdgar E. Iglesias TCGv_i32 t0; 710faa48d74SEdgar E. Iglesias unsigned int imm_w, imm_s; 711d09b2585SEdgar E. Iglesias bool s, t, e = false, i = false; 712fcf5ef2aSThomas Huth 7139ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) { 714fcf5ef2aSThomas Huth return; 715fcf5ef2aSThomas Huth } 716fcf5ef2aSThomas Huth 717faa48d74SEdgar E. Iglesias if (dc->type_b) { 718faa48d74SEdgar E. Iglesias /* Insert and extract are only available in immediate mode. */ 719d09b2585SEdgar E. Iglesias i = extract32(dc->imm, 15, 1); 720faa48d74SEdgar E. Iglesias e = extract32(dc->imm, 14, 1); 721faa48d74SEdgar E. Iglesias } 722e3e84983SEdgar E. Iglesias s = extract32(dc->imm, 10, 1); 723e3e84983SEdgar E. Iglesias t = extract32(dc->imm, 9, 1); 724faa48d74SEdgar E. Iglesias imm_w = extract32(dc->imm, 6, 5); 725faa48d74SEdgar E. Iglesias imm_s = extract32(dc->imm, 0, 5); 726fcf5ef2aSThomas Huth 727faa48d74SEdgar E. Iglesias if (e) { 728faa48d74SEdgar E. Iglesias if (imm_w + imm_s > 32 || imm_w == 0) { 729faa48d74SEdgar E. Iglesias /* These inputs have an undefined behavior. */ 730faa48d74SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 731faa48d74SEdgar E. Iglesias imm_w, imm_s); 732faa48d74SEdgar E. Iglesias } else { 733faa48d74SEdgar E. Iglesias tcg_gen_extract_i32(cpu_R[dc->rd], cpu_R[dc->ra], imm_s, imm_w); 734faa48d74SEdgar E. Iglesias } 735d09b2585SEdgar E. Iglesias } else if (i) { 736d09b2585SEdgar E. Iglesias int width = imm_w - imm_s + 1; 737d09b2585SEdgar E. Iglesias 738d09b2585SEdgar E. Iglesias if (imm_w < imm_s) { 739d09b2585SEdgar E. Iglesias /* These inputs have an undefined behavior. */ 740d09b2585SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 741d09b2585SEdgar E. Iglesias imm_w, imm_s); 742d09b2585SEdgar E. Iglesias } else { 743d09b2585SEdgar E. Iglesias tcg_gen_deposit_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_R[dc->ra], 744d09b2585SEdgar E. Iglesias imm_s, width); 745d09b2585SEdgar E. Iglesias } 746faa48d74SEdgar E. Iglesias } else { 747cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 748fcf5ef2aSThomas Huth 749cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc))); 750cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, 31); 751fcf5ef2aSThomas Huth 7522acf6d53SEdgar E. Iglesias if (s) { 753cfeea807SEdgar E. Iglesias tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7542acf6d53SEdgar E. Iglesias } else { 7552acf6d53SEdgar E. Iglesias if (t) { 756cfeea807SEdgar E. Iglesias tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7572acf6d53SEdgar E. Iglesias } else { 758cfeea807SEdgar E. Iglesias tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 759fcf5ef2aSThomas Huth } 760fcf5ef2aSThomas Huth } 761cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 7622acf6d53SEdgar E. Iglesias } 763faa48d74SEdgar E. Iglesias } 764fcf5ef2aSThomas Huth 765fcf5ef2aSThomas Huth static void dec_bit(DisasContext *dc) 766fcf5ef2aSThomas Huth { 767fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 768cfeea807SEdgar E. Iglesias TCGv_i32 t0; 769fcf5ef2aSThomas Huth unsigned int op; 770fcf5ef2aSThomas Huth 771fcf5ef2aSThomas Huth op = dc->ir & ((1 << 9) - 1); 772fcf5ef2aSThomas Huth switch (op) { 773fcf5ef2aSThomas Huth case 0x21: 774fcf5ef2aSThomas Huth /* src. */ 775cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 776fcf5ef2aSThomas Huth 7771074c0fbSRichard Henderson tcg_gen_shli_i32(t0, cpu_msr_c, 31); 7781074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); 779fcf5ef2aSThomas Huth if (dc->rd) { 780cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 781cfeea807SEdgar E. Iglesias tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0); 782fcf5ef2aSThomas Huth } 783cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 784fcf5ef2aSThomas Huth break; 785fcf5ef2aSThomas Huth 786fcf5ef2aSThomas Huth case 0x1: 787fcf5ef2aSThomas Huth case 0x41: 788fcf5ef2aSThomas Huth /* srl. */ 7891074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); 790fcf5ef2aSThomas Huth if (dc->rd) { 791fcf5ef2aSThomas Huth if (op == 0x41) 792cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 793fcf5ef2aSThomas Huth else 794cfeea807SEdgar E. Iglesias tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 795fcf5ef2aSThomas Huth } 796fcf5ef2aSThomas Huth break; 797fcf5ef2aSThomas Huth case 0x60: 798fcf5ef2aSThomas Huth tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 799fcf5ef2aSThomas Huth break; 800fcf5ef2aSThomas Huth case 0x61: 801fcf5ef2aSThomas Huth tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 802fcf5ef2aSThomas Huth break; 803fcf5ef2aSThomas Huth case 0x64: 804fcf5ef2aSThomas Huth case 0x66: 805fcf5ef2aSThomas Huth case 0x74: 806fcf5ef2aSThomas Huth case 0x76: 807fcf5ef2aSThomas Huth /* wdc. */ 808bdfc1e88SEdgar E. Iglesias trap_userspace(dc, true); 809fcf5ef2aSThomas Huth break; 810fcf5ef2aSThomas Huth case 0x68: 811fcf5ef2aSThomas Huth /* wic. */ 812bdfc1e88SEdgar E. Iglesias trap_userspace(dc, true); 813fcf5ef2aSThomas Huth break; 814fcf5ef2aSThomas Huth case 0xe0: 8159ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { 8169ba8cd45SEdgar E. Iglesias return; 817fcf5ef2aSThomas Huth } 8188fc5239eSEdgar E. Iglesias if (dc->cpu->cfg.use_pcmp_instr) { 8195318420cSRichard Henderson tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32); 820fcf5ef2aSThomas Huth } 821fcf5ef2aSThomas Huth break; 822fcf5ef2aSThomas Huth case 0x1e0: 823fcf5ef2aSThomas Huth /* swapb */ 824fcf5ef2aSThomas Huth tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 825fcf5ef2aSThomas Huth break; 826fcf5ef2aSThomas Huth case 0x1e2: 827fcf5ef2aSThomas Huth /*swaph */ 828fcf5ef2aSThomas Huth tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16); 829fcf5ef2aSThomas Huth break; 830fcf5ef2aSThomas Huth default: 831fcf5ef2aSThomas Huth cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", 832d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, op, dc->rd, dc->ra, dc->rb); 833fcf5ef2aSThomas Huth break; 834fcf5ef2aSThomas Huth } 835fcf5ef2aSThomas Huth } 836fcf5ef2aSThomas Huth 837fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc) 838fcf5ef2aSThomas Huth { 839fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 840fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT) { 8419b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 842fcf5ef2aSThomas Huth } 843fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 8440f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 845fcf5ef2aSThomas Huth } 846fcf5ef2aSThomas Huth } 847fcf5ef2aSThomas Huth 848fcf5ef2aSThomas Huth static void dec_imm(DisasContext *dc) 849fcf5ef2aSThomas Huth { 850d7ecb757SRichard Henderson dc->ext_imm = dc->imm << 16; 851d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 852fcf5ef2aSThomas Huth dc->tb_flags |= IMM_FLAG; 853fcf5ef2aSThomas Huth dc->clear_imm = 0; 854fcf5ef2aSThomas Huth } 855fcf5ef2aSThomas Huth 856d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) 857fcf5ef2aSThomas Huth { 8580e9033c8SEdgar E. Iglesias /* Should be set to true if r1 is used by loadstores. */ 8590e9033c8SEdgar E. Iglesias bool stackprot = false; 860403322eaSEdgar E. Iglesias TCGv_i32 t32; 861fcf5ef2aSThomas Huth 862fcf5ef2aSThomas Huth /* All load/stores use ra. */ 863fcf5ef2aSThomas Huth if (dc->ra == 1 && dc->cpu->cfg.stackprot) { 8640e9033c8SEdgar E. Iglesias stackprot = true; 865fcf5ef2aSThomas Huth } 866fcf5ef2aSThomas Huth 867fcf5ef2aSThomas Huth /* Treat the common cases first. */ 868fcf5ef2aSThomas Huth if (!dc->type_b) { 869d248e1beSEdgar E. Iglesias if (ea) { 870d248e1beSEdgar E. Iglesias int addr_size = dc->cpu->cfg.addr_size; 871d248e1beSEdgar E. Iglesias 872d248e1beSEdgar E. Iglesias if (addr_size == 32) { 873d248e1beSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 874d248e1beSEdgar E. Iglesias return; 875d248e1beSEdgar E. Iglesias } 876d248e1beSEdgar E. Iglesias 877d248e1beSEdgar E. Iglesias tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]); 878d248e1beSEdgar E. Iglesias if (addr_size < 64) { 879d248e1beSEdgar E. Iglesias /* Mask off out of range bits. */ 880d248e1beSEdgar E. Iglesias tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size)); 881d248e1beSEdgar E. Iglesias } 882d248e1beSEdgar E. Iglesias return; 883d248e1beSEdgar E. Iglesias } 884d248e1beSEdgar E. Iglesias 8850dc4af5cSEdgar E. Iglesias /* If any of the regs is r0, set t to the value of the other reg. */ 886fcf5ef2aSThomas Huth if (dc->ra == 0) { 887403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 8880dc4af5cSEdgar E. Iglesias return; 889fcf5ef2aSThomas Huth } else if (dc->rb == 0) { 890403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]); 8910dc4af5cSEdgar E. Iglesias return; 892fcf5ef2aSThomas Huth } 893fcf5ef2aSThomas Huth 894fcf5ef2aSThomas Huth if (dc->rb == 1 && dc->cpu->cfg.stackprot) { 8950e9033c8SEdgar E. Iglesias stackprot = true; 896fcf5ef2aSThomas Huth } 897fcf5ef2aSThomas Huth 898403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 899403322eaSEdgar E. Iglesias tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]); 900403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 901403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 902fcf5ef2aSThomas Huth 903fcf5ef2aSThomas Huth if (stackprot) { 9040a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 905fcf5ef2aSThomas Huth } 9060dc4af5cSEdgar E. Iglesias return; 907fcf5ef2aSThomas Huth } 908fcf5ef2aSThomas Huth /* Immediate. */ 909403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 910d7ecb757SRichard Henderson tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc)); 911403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 912403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 913fcf5ef2aSThomas Huth 914fcf5ef2aSThomas Huth if (stackprot) { 9150a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 916fcf5ef2aSThomas Huth } 9170dc4af5cSEdgar E. Iglesias return; 918fcf5ef2aSThomas Huth } 919fcf5ef2aSThomas Huth 920fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc) 921fcf5ef2aSThomas Huth { 922403322eaSEdgar E. Iglesias TCGv_i32 v; 923403322eaSEdgar E. Iglesias TCGv addr; 9248534063aSEdgar E. Iglesias unsigned int size; 925d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 926d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 92714776ab5STony Nguyen MemOp mop; 928fcf5ef2aSThomas Huth 929fcf5ef2aSThomas Huth mop = dc->opcode & 3; 930fcf5ef2aSThomas Huth size = 1 << mop; 931fcf5ef2aSThomas Huth if (!dc->type_b) { 932d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 9338534063aSEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 9348534063aSEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 935fcf5ef2aSThomas Huth } 936fcf5ef2aSThomas Huth mop |= MO_TE; 937fcf5ef2aSThomas Huth if (rev) { 938fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 939fcf5ef2aSThomas Huth } 940fcf5ef2aSThomas Huth 9419ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 942fcf5ef2aSThomas Huth return; 943fcf5ef2aSThomas Huth } 944fcf5ef2aSThomas Huth 945d248e1beSEdgar E. Iglesias if (trap_userspace(dc, ea)) { 946d248e1beSEdgar E. Iglesias return; 947d248e1beSEdgar E. Iglesias } 948d248e1beSEdgar E. Iglesias 949fcf5ef2aSThomas Huth t_sync_flags(dc); 950403322eaSEdgar E. Iglesias addr = tcg_temp_new(); 951d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 952d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 953d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 954fcf5ef2aSThomas Huth 955fcf5ef2aSThomas Huth /* 956fcf5ef2aSThomas Huth * When doing reverse accesses we need to do two things. 957fcf5ef2aSThomas Huth * 958fcf5ef2aSThomas Huth * 1. Reverse the address wrt endianness. 959fcf5ef2aSThomas Huth * 2. Byteswap the data lanes on the way back into the CPU core. 960fcf5ef2aSThomas Huth */ 961fcf5ef2aSThomas Huth if (rev && size != 4) { 962fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 963fcf5ef2aSThomas Huth switch (size) { 964fcf5ef2aSThomas Huth case 1: 965fcf5ef2aSThomas Huth { 966a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 967fcf5ef2aSThomas Huth break; 968fcf5ef2aSThomas Huth } 969fcf5ef2aSThomas Huth 970fcf5ef2aSThomas Huth case 2: 971fcf5ef2aSThomas Huth /* 00 -> 10 972fcf5ef2aSThomas Huth 10 -> 00. */ 973403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 974fcf5ef2aSThomas Huth break; 975fcf5ef2aSThomas Huth default: 976fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 977fcf5ef2aSThomas Huth break; 978fcf5ef2aSThomas Huth } 979fcf5ef2aSThomas Huth } 980fcf5ef2aSThomas Huth 981fcf5ef2aSThomas Huth /* lwx does not throw unaligned access errors, so force alignment */ 982fcf5ef2aSThomas Huth if (ex) { 983403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 984fcf5ef2aSThomas Huth } 985fcf5ef2aSThomas Huth 986fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 987fcf5ef2aSThomas Huth sync_jmpstate(dc); 988fcf5ef2aSThomas Huth 989fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 990fcf5ef2aSThomas Huth /* 991fcf5ef2aSThomas Huth * Microblaze gives MMU faults priority over faults due to 992fcf5ef2aSThomas Huth * unaligned addresses. That's why we speculatively do the load 993fcf5ef2aSThomas Huth * into v. If the load succeeds, we verify alignment of the 994fcf5ef2aSThomas Huth * address and if that succeeds we write into the destination reg. 995fcf5ef2aSThomas Huth */ 996cfeea807SEdgar E. Iglesias v = tcg_temp_new_i32(); 997d248e1beSEdgar E. Iglesias tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); 998fcf5ef2aSThomas Huth 9991507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1000a6338015SEdgar E. Iglesias TCGv_i32 t0 = tcg_const_i32(0); 1001a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1002a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1003a6338015SEdgar E. Iglesias 1004d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1005a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t0, tsize); 1006a6338015SEdgar E. Iglesias 1007a6338015SEdgar E. Iglesias tcg_temp_free_i32(t0); 1008a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1009a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1010fcf5ef2aSThomas Huth } 1011fcf5ef2aSThomas Huth 1012fcf5ef2aSThomas Huth if (ex) { 10139b158558SRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 10149b158558SRichard Henderson tcg_gen_mov_i32(cpu_res_val, v); 1015fcf5ef2aSThomas Huth } 1016fcf5ef2aSThomas Huth if (dc->rd) { 1017cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(cpu_R[dc->rd], v); 1018fcf5ef2aSThomas Huth } 1019cfeea807SEdgar E. Iglesias tcg_temp_free_i32(v); 1020fcf5ef2aSThomas Huth 1021fcf5ef2aSThomas Huth if (ex) { /* lwx */ 1022fcf5ef2aSThomas Huth /* no support for AXI exclusive so always clear C */ 10231074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1024fcf5ef2aSThomas Huth } 1025fcf5ef2aSThomas Huth 1026403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1027fcf5ef2aSThomas Huth } 1028fcf5ef2aSThomas Huth 1029fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc) 1030fcf5ef2aSThomas Huth { 1031403322eaSEdgar E. Iglesias TCGv addr; 1032fcf5ef2aSThomas Huth TCGLabel *swx_skip = NULL; 1033b51b3d43SEdgar E. Iglesias unsigned int size; 1034d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 1035d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 103614776ab5STony Nguyen MemOp mop; 1037fcf5ef2aSThomas Huth 1038fcf5ef2aSThomas Huth mop = dc->opcode & 3; 1039fcf5ef2aSThomas Huth size = 1 << mop; 1040fcf5ef2aSThomas Huth if (!dc->type_b) { 1041d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 1042b51b3d43SEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 1043b51b3d43SEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 1044fcf5ef2aSThomas Huth } 1045fcf5ef2aSThomas Huth mop |= MO_TE; 1046fcf5ef2aSThomas Huth if (rev) { 1047fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 1048fcf5ef2aSThomas Huth } 1049fcf5ef2aSThomas Huth 10509ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 1051fcf5ef2aSThomas Huth return; 1052fcf5ef2aSThomas Huth } 1053fcf5ef2aSThomas Huth 1054d248e1beSEdgar E. Iglesias trap_userspace(dc, ea); 1055d248e1beSEdgar E. Iglesias 1056fcf5ef2aSThomas Huth t_sync_flags(dc); 1057fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 1058fcf5ef2aSThomas Huth sync_jmpstate(dc); 10590dc4af5cSEdgar E. Iglesias /* SWX needs a temp_local. */ 1060403322eaSEdgar E. Iglesias addr = ex ? tcg_temp_local_new() : tcg_temp_new(); 1061d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 1062d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 1063d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 1064fcf5ef2aSThomas Huth 1065fcf5ef2aSThomas Huth if (ex) { /* swx */ 1066cfeea807SEdgar E. Iglesias TCGv_i32 tval; 1067fcf5ef2aSThomas Huth 1068fcf5ef2aSThomas Huth /* swx does not throw unaligned access errors, so force alignment */ 1069403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 1070fcf5ef2aSThomas Huth 10711074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1072fcf5ef2aSThomas Huth swx_skip = gen_new_label(); 10739b158558SRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); 1074fcf5ef2aSThomas Huth 1075071cdc67SEdgar E. Iglesias /* 1076071cdc67SEdgar E. Iglesias * Compare the value loaded at lwx with current contents of 1077071cdc67SEdgar E. Iglesias * the reserved location. 1078071cdc67SEdgar E. Iglesias */ 1079cfeea807SEdgar E. Iglesias tval = tcg_temp_new_i32(); 1080071cdc67SEdgar E. Iglesias 10819b158558SRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val, 1082071cdc67SEdgar E. Iglesias cpu_R[dc->rd], mem_index, 1083071cdc67SEdgar E. Iglesias mop); 1084071cdc67SEdgar E. Iglesias 10859b158558SRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); 10861074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1087cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tval); 1088fcf5ef2aSThomas Huth } 1089fcf5ef2aSThomas Huth 1090fcf5ef2aSThomas Huth if (rev && size != 4) { 1091fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 1092fcf5ef2aSThomas Huth switch (size) { 1093fcf5ef2aSThomas Huth case 1: 1094fcf5ef2aSThomas Huth { 1095a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 1096fcf5ef2aSThomas Huth break; 1097fcf5ef2aSThomas Huth } 1098fcf5ef2aSThomas Huth 1099fcf5ef2aSThomas Huth case 2: 1100fcf5ef2aSThomas Huth /* 00 -> 10 1101fcf5ef2aSThomas Huth 10 -> 00. */ 1102fcf5ef2aSThomas Huth /* Force addr into the temp. */ 1103403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 1104fcf5ef2aSThomas Huth break; 1105fcf5ef2aSThomas Huth default: 1106fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 1107fcf5ef2aSThomas Huth break; 1108fcf5ef2aSThomas Huth } 1109fcf5ef2aSThomas Huth } 1110071cdc67SEdgar E. Iglesias 1111071cdc67SEdgar E. Iglesias if (!ex) { 1112d248e1beSEdgar E. Iglesias tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); 1113071cdc67SEdgar E. Iglesias } 1114fcf5ef2aSThomas Huth 1115fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 11161507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1117a6338015SEdgar E. Iglesias TCGv_i32 t1 = tcg_const_i32(1); 1118a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1119a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1120a6338015SEdgar E. Iglesias 1121d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1122fcf5ef2aSThomas Huth /* FIXME: if the alignment is wrong, we should restore the value 1123fcf5ef2aSThomas Huth * in memory. One possible way to achieve this is to probe 1124fcf5ef2aSThomas Huth * the MMU prior to the memaccess, thay way we could put 1125fcf5ef2aSThomas Huth * the alignment checks in between the probe and the mem 1126fcf5ef2aSThomas Huth * access. 1127fcf5ef2aSThomas Huth */ 1128a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t1, tsize); 1129a6338015SEdgar E. Iglesias 1130a6338015SEdgar E. Iglesias tcg_temp_free_i32(t1); 1131a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1132a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1133fcf5ef2aSThomas Huth } 1134fcf5ef2aSThomas Huth 1135fcf5ef2aSThomas Huth if (ex) { 1136fcf5ef2aSThomas Huth gen_set_label(swx_skip); 1137fcf5ef2aSThomas Huth } 1138fcf5ef2aSThomas Huth 1139403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1140fcf5ef2aSThomas Huth } 1141fcf5ef2aSThomas Huth 1142fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc, 11439e6e1828SEdgar E. Iglesias TCGv_i32 d, TCGv_i32 a) 1144fcf5ef2aSThomas Huth { 1145d89b86e9SEdgar E. Iglesias static const int mb_to_tcg_cc[] = { 1146d89b86e9SEdgar E. Iglesias [CC_EQ] = TCG_COND_EQ, 1147d89b86e9SEdgar E. Iglesias [CC_NE] = TCG_COND_NE, 1148d89b86e9SEdgar E. Iglesias [CC_LT] = TCG_COND_LT, 1149d89b86e9SEdgar E. Iglesias [CC_LE] = TCG_COND_LE, 1150d89b86e9SEdgar E. Iglesias [CC_GE] = TCG_COND_GE, 1151d89b86e9SEdgar E. Iglesias [CC_GT] = TCG_COND_GT, 1152d89b86e9SEdgar E. Iglesias }; 1153d89b86e9SEdgar E. Iglesias 1154fcf5ef2aSThomas Huth switch (cc) { 1155fcf5ef2aSThomas Huth case CC_EQ: 1156fcf5ef2aSThomas Huth case CC_NE: 1157fcf5ef2aSThomas Huth case CC_LT: 1158fcf5ef2aSThomas Huth case CC_LE: 1159fcf5ef2aSThomas Huth case CC_GE: 1160fcf5ef2aSThomas Huth case CC_GT: 11619e6e1828SEdgar E. Iglesias tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); 1162fcf5ef2aSThomas Huth break; 1163fcf5ef2aSThomas Huth default: 1164fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); 1165fcf5ef2aSThomas Huth break; 1166fcf5ef2aSThomas Huth } 1167fcf5ef2aSThomas Huth } 1168fcf5ef2aSThomas Huth 11690f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) 1170fcf5ef2aSThomas Huth { 11710f96e96bSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 1172e956caf2SEdgar E. Iglesias 11730f96e96bSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, 11749b158558SRichard Henderson cpu_btaken, zero, 1175e956caf2SEdgar E. Iglesias pc_true, pc_false); 1176e956caf2SEdgar E. Iglesias 11770f96e96bSRichard Henderson tcg_temp_free_i32(zero); 1178fcf5ef2aSThomas Huth } 1179fcf5ef2aSThomas Huth 1180f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1181f91c60f0SEdgar E. Iglesias { 1182f91c60f0SEdgar E. Iglesias TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)); 1183f91c60f0SEdgar E. Iglesias 1184f91c60f0SEdgar E. Iglesias dc->delayed_branch = 2; 1185f91c60f0SEdgar E. Iglesias dc->tb_flags |= D_FLAG; 1186f91c60f0SEdgar E. Iglesias 1187f91c60f0SEdgar E. Iglesias tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm)); 1188f91c60f0SEdgar E. Iglesias tcg_temp_free_i32(tmp); 1189f91c60f0SEdgar E. Iglesias } 1190f91c60f0SEdgar E. Iglesias 1191fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc) 1192fcf5ef2aSThomas Huth { 1193fcf5ef2aSThomas Huth unsigned int cc; 1194fcf5ef2aSThomas Huth unsigned int dslot; 1195fcf5ef2aSThomas Huth 1196fcf5ef2aSThomas Huth cc = EXTRACT_FIELD(dc->ir, 21, 23); 1197fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 25); 1198fcf5ef2aSThomas Huth 1199fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1200fcf5ef2aSThomas Huth if (dslot) { 1201f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1202fcf5ef2aSThomas Huth } 1203fcf5ef2aSThomas Huth 1204d7ecb757SRichard Henderson if (dc->type_b) { 1205fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT_CC; 1206d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1207d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1208fcf5ef2aSThomas Huth } else { 1209fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 1210d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1211fcf5ef2aSThomas Huth } 12129b158558SRichard Henderson eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); 1213fcf5ef2aSThomas Huth } 1214fcf5ef2aSThomas Huth 1215fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc) 1216fcf5ef2aSThomas Huth { 1217fcf5ef2aSThomas Huth unsigned int dslot, link, abs, mbar; 1218fcf5ef2aSThomas Huth 1219fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 20); 1220fcf5ef2aSThomas Huth abs = dc->ir & (1 << 19); 1221fcf5ef2aSThomas Huth link = dc->ir & (1 << 18); 1222fcf5ef2aSThomas Huth 1223fcf5ef2aSThomas Huth /* Memory barrier. */ 1224fcf5ef2aSThomas Huth mbar = (dc->ir >> 16) & 31; 1225fcf5ef2aSThomas Huth if (mbar == 2 && dc->imm == 4) { 1226badcbf9dSEdgar E. Iglesias uint16_t mbar_imm = dc->rd; 1227badcbf9dSEdgar E. Iglesias 12283f172744SEdgar E. Iglesias /* Data access memory barrier. */ 12293f172744SEdgar E. Iglesias if ((mbar_imm & 2) == 0) { 12303f172744SEdgar E. Iglesias tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 12313f172744SEdgar E. Iglesias } 12323f172744SEdgar E. Iglesias 1233fcf5ef2aSThomas Huth /* mbar IMM & 16 decodes to sleep. */ 1234badcbf9dSEdgar E. Iglesias if (mbar_imm & 16) { 123541ba37c4SRichard Henderson TCGv_i32 tmp_1; 1236fcf5ef2aSThomas Huth 1237b4919e7dSEdgar E. Iglesias if (trap_userspace(dc, true)) { 1238b4919e7dSEdgar E. Iglesias /* Sleep is a privileged instruction. */ 1239b4919e7dSEdgar E. Iglesias return; 1240b4919e7dSEdgar E. Iglesias } 1241b4919e7dSEdgar E. Iglesias 1242fcf5ef2aSThomas Huth t_sync_flags(dc); 124341ba37c4SRichard Henderson 124441ba37c4SRichard Henderson tmp_1 = tcg_const_i32(1); 1245fcf5ef2aSThomas Huth tcg_gen_st_i32(tmp_1, cpu_env, 1246fcf5ef2aSThomas Huth -offsetof(MicroBlazeCPU, env) 1247fcf5ef2aSThomas Huth +offsetof(CPUState, halted)); 1248fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp_1); 124941ba37c4SRichard Henderson 1250d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 125141ba37c4SRichard Henderson 125241ba37c4SRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1253fcf5ef2aSThomas Huth return; 1254fcf5ef2aSThomas Huth } 1255fcf5ef2aSThomas Huth /* Break the TB. */ 1256fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 1257fcf5ef2aSThomas Huth return; 1258fcf5ef2aSThomas Huth } 1259fcf5ef2aSThomas Huth 1260d7ecb757SRichard Henderson if (abs && link && !dslot) { 1261d7ecb757SRichard Henderson if (dc->type_b) { 1262d7ecb757SRichard Henderson /* BRKI */ 1263d7ecb757SRichard Henderson uint32_t imm = dec_alu_typeb_imm(dc); 1264d7ecb757SRichard Henderson if (trap_userspace(dc, imm != 8 && imm != 0x18)) { 1265d7ecb757SRichard Henderson return; 1266d7ecb757SRichard Henderson } 1267d7ecb757SRichard Henderson } else { 1268d7ecb757SRichard Henderson /* BRK */ 1269d7ecb757SRichard Henderson if (trap_userspace(dc, true)) { 1270d7ecb757SRichard Henderson return; 1271d7ecb757SRichard Henderson } 1272d7ecb757SRichard Henderson } 1273d7ecb757SRichard Henderson } 1274d7ecb757SRichard Henderson 1275fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1276fcf5ef2aSThomas Huth if (dslot) { 1277f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1278fcf5ef2aSThomas Huth } 1279d7ecb757SRichard Henderson if (link && dc->rd) { 1280d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1281d7ecb757SRichard Henderson } 1282fcf5ef2aSThomas Huth 1283fcf5ef2aSThomas Huth if (abs) { 1284d7ecb757SRichard Henderson if (dc->type_b) { 1285d7ecb757SRichard Henderson uint32_t dest = dec_alu_typeb_imm(dc); 1286d7ecb757SRichard Henderson 1287d7ecb757SRichard Henderson dc->jmp = JMP_DIRECT; 1288d7ecb757SRichard Henderson dc->jmp_pc = dest; 1289d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dest); 1290fcf5ef2aSThomas Huth if (link && !dslot) { 1291d7ecb757SRichard Henderson switch (dest) { 1292d7ecb757SRichard Henderson case 8: 1293d7ecb757SRichard Henderson case 0x18: 1294d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 1295d7ecb757SRichard Henderson break; 1296d7ecb757SRichard Henderson case 0: 1297d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1298d7ecb757SRichard Henderson break; 1299d7ecb757SRichard Henderson } 1300d7ecb757SRichard Henderson } 1301d7ecb757SRichard Henderson } else { 1302d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1303d7ecb757SRichard Henderson tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]); 1304d7ecb757SRichard Henderson if (link && !dslot) { 130541ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 130641ba37c4SRichard Henderson } 1307fcf5ef2aSThomas Huth } 1308d7ecb757SRichard Henderson } else if (dc->type_b) { 1309fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT; 1310d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1311d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1312fcf5ef2aSThomas Huth } else { 1313d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1314d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1315d7ecb757SRichard Henderson } 13169b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 1317fcf5ef2aSThomas Huth } 1318fcf5ef2aSThomas Huth 1319fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc) 1320fcf5ef2aSThomas Huth { 1321cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1322cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1323cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13243e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13250a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 13260a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1327cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1328fcf5ef2aSThomas Huth 1329cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1330cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1331fcf5ef2aSThomas Huth msr_write(dc, t1); 1332cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1333cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1334fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1335fcf5ef2aSThomas Huth } 1336fcf5ef2aSThomas Huth 1337fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc) 1338fcf5ef2aSThomas Huth { 1339cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1340cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1341cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13423e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13430a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1344cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1345cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1346fcf5ef2aSThomas Huth 1347cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1348cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1349fcf5ef2aSThomas Huth msr_write(dc, t1); 1350cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1351cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1352fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1353fcf5ef2aSThomas Huth } 1354fcf5ef2aSThomas Huth 1355fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc) 1356fcf5ef2aSThomas Huth { 1357cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1358cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1359cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1360fcf5ef2aSThomas Huth 13613e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13620a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1363cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1364cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1365cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1366fcf5ef2aSThomas Huth 1367cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1368cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1369fcf5ef2aSThomas Huth msr_write(dc, t1); 1370cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1371cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1372fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1373fcf5ef2aSThomas Huth } 1374fcf5ef2aSThomas Huth 1375fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc) 1376fcf5ef2aSThomas Huth { 1377fcf5ef2aSThomas Huth unsigned int b_bit, i_bit, e_bit; 1378fcf5ef2aSThomas Huth 1379fcf5ef2aSThomas Huth i_bit = dc->ir & (1 << 21); 1380fcf5ef2aSThomas Huth b_bit = dc->ir & (1 << 22); 1381fcf5ef2aSThomas Huth e_bit = dc->ir & (1 << 23); 1382fcf5ef2aSThomas Huth 1383bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1384bdfc1e88SEdgar E. Iglesias return; 1385bdfc1e88SEdgar E. Iglesias } 1386bdfc1e88SEdgar E. Iglesias 1387f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1388fcf5ef2aSThomas Huth 1389fcf5ef2aSThomas Huth if (i_bit) { 1390fcf5ef2aSThomas Huth dc->tb_flags |= DRTI_FLAG; 1391fcf5ef2aSThomas Huth } else if (b_bit) { 1392fcf5ef2aSThomas Huth dc->tb_flags |= DRTB_FLAG; 1393fcf5ef2aSThomas Huth } else if (e_bit) { 1394fcf5ef2aSThomas Huth dc->tb_flags |= DRTE_FLAG; 139511105d67SRichard Henderson } 1396fcf5ef2aSThomas Huth 1397fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 13989b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 13990f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 1400fcf5ef2aSThomas Huth } 1401fcf5ef2aSThomas Huth 1402fcf5ef2aSThomas Huth static int dec_check_fpuv2(DisasContext *dc) 1403fcf5ef2aSThomas Huth { 1404fcf5ef2aSThomas Huth if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { 140541ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_FPU); 1406fcf5ef2aSThomas Huth } 14072016a6a7SJoe Komlodi return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; 1408fcf5ef2aSThomas Huth } 1409fcf5ef2aSThomas Huth 1410fcf5ef2aSThomas Huth static void dec_fpu(DisasContext *dc) 1411fcf5ef2aSThomas Huth { 1412fcf5ef2aSThomas Huth unsigned int fpu_insn; 1413fcf5ef2aSThomas Huth 14149ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) { 1415fcf5ef2aSThomas Huth return; 1416fcf5ef2aSThomas Huth } 1417fcf5ef2aSThomas Huth 1418fcf5ef2aSThomas Huth fpu_insn = (dc->ir >> 7) & 7; 1419fcf5ef2aSThomas Huth 1420fcf5ef2aSThomas Huth switch (fpu_insn) { 1421fcf5ef2aSThomas Huth case 0: 1422fcf5ef2aSThomas Huth gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1423fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1424fcf5ef2aSThomas Huth break; 1425fcf5ef2aSThomas Huth 1426fcf5ef2aSThomas Huth case 1: 1427fcf5ef2aSThomas Huth gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1428fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1429fcf5ef2aSThomas Huth break; 1430fcf5ef2aSThomas Huth 1431fcf5ef2aSThomas Huth case 2: 1432fcf5ef2aSThomas Huth gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1433fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1434fcf5ef2aSThomas Huth break; 1435fcf5ef2aSThomas Huth 1436fcf5ef2aSThomas Huth case 3: 1437fcf5ef2aSThomas Huth gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1438fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1439fcf5ef2aSThomas Huth break; 1440fcf5ef2aSThomas Huth 1441fcf5ef2aSThomas Huth case 4: 1442fcf5ef2aSThomas Huth switch ((dc->ir >> 4) & 7) { 1443fcf5ef2aSThomas Huth case 0: 1444fcf5ef2aSThomas Huth gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env, 1445fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1446fcf5ef2aSThomas Huth break; 1447fcf5ef2aSThomas Huth case 1: 1448fcf5ef2aSThomas Huth gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env, 1449fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1450fcf5ef2aSThomas Huth break; 1451fcf5ef2aSThomas Huth case 2: 1452fcf5ef2aSThomas Huth gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env, 1453fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1454fcf5ef2aSThomas Huth break; 1455fcf5ef2aSThomas Huth case 3: 1456fcf5ef2aSThomas Huth gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env, 1457fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1458fcf5ef2aSThomas Huth break; 1459fcf5ef2aSThomas Huth case 4: 1460fcf5ef2aSThomas Huth gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env, 1461fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1462fcf5ef2aSThomas Huth break; 1463fcf5ef2aSThomas Huth case 5: 1464fcf5ef2aSThomas Huth gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env, 1465fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1466fcf5ef2aSThomas Huth break; 1467fcf5ef2aSThomas Huth case 6: 1468fcf5ef2aSThomas Huth gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env, 1469fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1470fcf5ef2aSThomas Huth break; 1471fcf5ef2aSThomas Huth default: 1472fcf5ef2aSThomas Huth qemu_log_mask(LOG_UNIMP, 1473fcf5ef2aSThomas Huth "unimplemented fcmp fpu_insn=%x pc=%x" 1474fcf5ef2aSThomas Huth " opc=%x\n", 1475d4705ae0SRichard Henderson fpu_insn, (uint32_t)dc->base.pc_next, 1476d4705ae0SRichard Henderson dc->opcode); 1477fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1478fcf5ef2aSThomas Huth break; 1479fcf5ef2aSThomas Huth } 1480fcf5ef2aSThomas Huth break; 1481fcf5ef2aSThomas Huth 1482fcf5ef2aSThomas Huth case 5: 1483fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1484fcf5ef2aSThomas Huth return; 1485fcf5ef2aSThomas Huth } 1486fcf5ef2aSThomas Huth gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1487fcf5ef2aSThomas Huth break; 1488fcf5ef2aSThomas Huth 1489fcf5ef2aSThomas Huth case 6: 1490fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1491fcf5ef2aSThomas Huth return; 1492fcf5ef2aSThomas Huth } 1493fcf5ef2aSThomas Huth gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1494fcf5ef2aSThomas Huth break; 1495fcf5ef2aSThomas Huth 1496fcf5ef2aSThomas Huth case 7: 1497fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1498fcf5ef2aSThomas Huth return; 1499fcf5ef2aSThomas Huth } 1500fcf5ef2aSThomas Huth gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1501fcf5ef2aSThomas Huth break; 1502fcf5ef2aSThomas Huth 1503fcf5ef2aSThomas Huth default: 1504fcf5ef2aSThomas Huth qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x" 1505fcf5ef2aSThomas Huth " opc=%x\n", 1506d4705ae0SRichard Henderson fpu_insn, (uint32_t)dc->base.pc_next, dc->opcode); 1507fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1508fcf5ef2aSThomas Huth break; 1509fcf5ef2aSThomas Huth } 1510fcf5ef2aSThomas Huth } 1511fcf5ef2aSThomas Huth 1512fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc) 1513fcf5ef2aSThomas Huth { 15149ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 1515fcf5ef2aSThomas Huth return; 1516fcf5ef2aSThomas Huth } 1517d4705ae0SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", 1518d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, dc->opcode); 1519fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1520fcf5ef2aSThomas Huth } 1521fcf5ef2aSThomas Huth 1522fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 1523fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc) 1524fcf5ef2aSThomas Huth { 1525fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1526fcf5ef2aSThomas Huth int ctrl; 1527fcf5ef2aSThomas Huth 1528bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 1529fcf5ef2aSThomas Huth return; 1530fcf5ef2aSThomas Huth } 1531fcf5ef2aSThomas Huth 1532cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 1533fcf5ef2aSThomas Huth if (dc->type_b) { 1534cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 1535fcf5ef2aSThomas Huth ctrl = dc->imm >> 10; 1536fcf5ef2aSThomas Huth } else { 1537cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 1538fcf5ef2aSThomas Huth ctrl = dc->imm >> 5; 1539fcf5ef2aSThomas Huth } 1540fcf5ef2aSThomas Huth 1541cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 1542fcf5ef2aSThomas Huth 1543fcf5ef2aSThomas Huth if (dc->rd == 0) { 1544fcf5ef2aSThomas Huth gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 1545fcf5ef2aSThomas Huth } else { 1546fcf5ef2aSThomas Huth gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 1547fcf5ef2aSThomas Huth } 1548cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1549cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 1550fcf5ef2aSThomas Huth } 1551fcf5ef2aSThomas Huth 1552fcf5ef2aSThomas Huth static struct decoder_info { 1553fcf5ef2aSThomas Huth struct { 1554fcf5ef2aSThomas Huth uint32_t bits; 1555fcf5ef2aSThomas Huth uint32_t mask; 1556fcf5ef2aSThomas Huth }; 1557fcf5ef2aSThomas Huth void (*dec)(DisasContext *dc); 1558fcf5ef2aSThomas Huth } decinfo[] = { 1559fcf5ef2aSThomas Huth {DEC_BIT, dec_bit}, 1560fcf5ef2aSThomas Huth {DEC_BARREL, dec_barrel}, 1561fcf5ef2aSThomas Huth {DEC_LD, dec_load}, 1562fcf5ef2aSThomas Huth {DEC_ST, dec_store}, 1563fcf5ef2aSThomas Huth {DEC_IMM, dec_imm}, 1564fcf5ef2aSThomas Huth {DEC_BR, dec_br}, 1565fcf5ef2aSThomas Huth {DEC_BCC, dec_bcc}, 1566fcf5ef2aSThomas Huth {DEC_RTS, dec_rts}, 1567fcf5ef2aSThomas Huth {DEC_FPU, dec_fpu}, 1568fcf5ef2aSThomas Huth {DEC_DIV, dec_div}, 1569fcf5ef2aSThomas Huth {DEC_MSR, dec_msr}, 1570fcf5ef2aSThomas Huth {DEC_STREAM, dec_stream}, 1571fcf5ef2aSThomas Huth {{0, 0}, dec_null} 1572fcf5ef2aSThomas Huth }; 1573fcf5ef2aSThomas Huth 157444d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir) 1575fcf5ef2aSThomas Huth { 1576fcf5ef2aSThomas Huth int i; 1577fcf5ef2aSThomas Huth 1578fcf5ef2aSThomas Huth dc->ir = ir; 1579fcf5ef2aSThomas Huth 1580fcf5ef2aSThomas Huth /* bit 2 seems to indicate insn type. */ 1581fcf5ef2aSThomas Huth dc->type_b = ir & (1 << 29); 1582fcf5ef2aSThomas Huth 1583fcf5ef2aSThomas Huth dc->opcode = EXTRACT_FIELD(ir, 26, 31); 1584fcf5ef2aSThomas Huth dc->rd = EXTRACT_FIELD(ir, 21, 25); 1585fcf5ef2aSThomas Huth dc->ra = EXTRACT_FIELD(ir, 16, 20); 1586fcf5ef2aSThomas Huth dc->rb = EXTRACT_FIELD(ir, 11, 15); 1587fcf5ef2aSThomas Huth dc->imm = EXTRACT_FIELD(ir, 0, 15); 1588fcf5ef2aSThomas Huth 1589fcf5ef2aSThomas Huth /* Large switch for all insns. */ 1590fcf5ef2aSThomas Huth for (i = 0; i < ARRAY_SIZE(decinfo); i++) { 1591fcf5ef2aSThomas Huth if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { 1592fcf5ef2aSThomas Huth decinfo[i].dec(dc); 1593fcf5ef2aSThomas Huth break; 1594fcf5ef2aSThomas Huth } 1595fcf5ef2aSThomas Huth } 1596fcf5ef2aSThomas Huth } 1597fcf5ef2aSThomas Huth 1598372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1599fcf5ef2aSThomas Huth { 1600372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1601372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1602372122e3SRichard Henderson int bound; 1603fcf5ef2aSThomas Huth 1604fcf5ef2aSThomas Huth dc->cpu = cpu; 1605372122e3SRichard Henderson dc->synced_flags = dc->tb_flags = dc->base.tb->flags; 1606fcf5ef2aSThomas Huth dc->delayed_branch = !!(dc->tb_flags & D_FLAG); 1607372122e3SRichard Henderson dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; 1608fcf5ef2aSThomas Huth dc->cpustate_changed = 0; 1609fcf5ef2aSThomas Huth dc->abort_at_next_insn = 0; 1610d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 161120800179SRichard Henderson dc->r0 = NULL; 161220800179SRichard Henderson dc->r0_set = false; 1613fcf5ef2aSThomas Huth 1614372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1615372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1616fcf5ef2aSThomas Huth } 1617fcf5ef2aSThomas Huth 1618372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1619fcf5ef2aSThomas Huth { 1620fcf5ef2aSThomas Huth } 1621fcf5ef2aSThomas Huth 1622372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1623372122e3SRichard Henderson { 1624372122e3SRichard Henderson tcg_gen_insn_start(dcb->pc_next); 1625372122e3SRichard Henderson } 1626fcf5ef2aSThomas Huth 1627372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1628372122e3SRichard Henderson const CPUBreakpoint *bp) 1629372122e3SRichard Henderson { 1630372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1631372122e3SRichard Henderson 1632372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1633372122e3SRichard Henderson 1634372122e3SRichard Henderson /* 1635372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1636372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1637372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1638372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1639372122e3SRichard Henderson */ 1640372122e3SRichard Henderson dc->base.pc_next += 4; 1641372122e3SRichard Henderson return true; 1642372122e3SRichard Henderson } 1643372122e3SRichard Henderson 1644372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1645372122e3SRichard Henderson { 1646372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1647372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 164844d1432bSRichard Henderson uint32_t ir; 1649372122e3SRichard Henderson 1650372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1651372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1652372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1653372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1654fcf5ef2aSThomas Huth } 1655fcf5ef2aSThomas Huth 1656fcf5ef2aSThomas Huth dc->clear_imm = 1; 165744d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 165844d1432bSRichard Henderson if (!decode(dc, ir)) { 165944d1432bSRichard Henderson old_decode(dc, ir); 166044d1432bSRichard Henderson } 166120800179SRichard Henderson 166220800179SRichard Henderson if (dc->r0) { 166320800179SRichard Henderson tcg_temp_free_i32(dc->r0); 166420800179SRichard Henderson dc->r0 = NULL; 166520800179SRichard Henderson dc->r0_set = false; 166620800179SRichard Henderson } 166720800179SRichard Henderson 1668d7ecb757SRichard Henderson if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { 1669fcf5ef2aSThomas Huth dc->tb_flags &= ~IMM_FLAG; 1670d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1671372122e3SRichard Henderson } 1672d4705ae0SRichard Henderson dc->base.pc_next += 4; 1673fcf5ef2aSThomas Huth 1674372122e3SRichard Henderson if (dc->delayed_branch && --dc->delayed_branch == 0) { 1675372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 1676fcf5ef2aSThomas Huth do_rti(dc); 1677372122e3SRichard Henderson } 1678372122e3SRichard Henderson if (dc->tb_flags & DRTB_FLAG) { 1679fcf5ef2aSThomas Huth do_rtb(dc); 1680372122e3SRichard Henderson } 1681372122e3SRichard Henderson if (dc->tb_flags & DRTE_FLAG) { 1682fcf5ef2aSThomas Huth do_rte(dc); 1683372122e3SRichard Henderson } 1684fcf5ef2aSThomas Huth /* Clear the delay slot flag. */ 1685fcf5ef2aSThomas Huth dc->tb_flags &= ~D_FLAG; 1686372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1687372122e3SRichard Henderson } 1688372122e3SRichard Henderson 1689372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1690372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1691372122e3SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1692372122e3SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1693372122e3SRichard Henderson } 1694372122e3SRichard Henderson } 1695372122e3SRichard Henderson 1696372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1697372122e3SRichard Henderson { 1698372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1699372122e3SRichard Henderson 1700372122e3SRichard Henderson assert(!dc->abort_at_next_insn); 1701372122e3SRichard Henderson 1702372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1703372122e3SRichard Henderson /* We have already exited the TB. */ 1704372122e3SRichard Henderson return; 1705372122e3SRichard Henderson } 1706372122e3SRichard Henderson 1707372122e3SRichard Henderson t_sync_flags(dc); 1708372122e3SRichard Henderson if (dc->tb_flags & D_FLAG) { 1709372122e3SRichard Henderson sync_jmpstate(dc); 1710372122e3SRichard Henderson dc->jmp = JMP_NOJMP; 1711372122e3SRichard Henderson } 1712372122e3SRichard Henderson 1713372122e3SRichard Henderson switch (dc->base.is_jmp) { 1714372122e3SRichard Henderson case DISAS_TOO_MANY: 1715372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1716372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1717372122e3SRichard Henderson return; 1718372122e3SRichard Henderson 1719372122e3SRichard Henderson case DISAS_UPDATE: 1720372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1721372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1722372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1723372122e3SRichard Henderson } else { 1724372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1725372122e3SRichard Henderson } 1726372122e3SRichard Henderson return; 1727372122e3SRichard Henderson 1728372122e3SRichard Henderson case DISAS_JUMP: 1729372122e3SRichard Henderson switch (dc->jmp) { 1730372122e3SRichard Henderson case JMP_INDIRECT: 1731372122e3SRichard Henderson { 1732d4705ae0SRichard Henderson TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); 17330f96e96bSRichard Henderson eval_cond_jmp(dc, cpu_btarget, tmp_pc); 17340f96e96bSRichard Henderson tcg_temp_free_i32(tmp_pc); 1735372122e3SRichard Henderson 1736372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1737372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1738372122e3SRichard Henderson } else { 1739372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1740372122e3SRichard Henderson } 1741372122e3SRichard Henderson } 1742372122e3SRichard Henderson return; 1743372122e3SRichard Henderson 1744372122e3SRichard Henderson case JMP_DIRECT_CC: 1745372122e3SRichard Henderson { 1746fcf5ef2aSThomas Huth TCGLabel *l1 = gen_new_label(); 17479b158558SRichard Henderson tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); 1748d4705ae0SRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1749fcf5ef2aSThomas Huth gen_set_label(l1); 1750372122e3SRichard Henderson } 1751372122e3SRichard Henderson /* fall through */ 1752372122e3SRichard Henderson 1753372122e3SRichard Henderson case JMP_DIRECT: 1754fcf5ef2aSThomas Huth gen_goto_tb(dc, 0, dc->jmp_pc); 1755372122e3SRichard Henderson return; 1756fcf5ef2aSThomas Huth } 1757372122e3SRichard Henderson /* fall through */ 1758fcf5ef2aSThomas Huth 1759a2b80dbdSRichard Henderson default: 1760a2b80dbdSRichard Henderson g_assert_not_reached(); 1761fcf5ef2aSThomas Huth } 1762fcf5ef2aSThomas Huth } 1763fcf5ef2aSThomas Huth 1764372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1765372122e3SRichard Henderson { 1766372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1767372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 1768fcf5ef2aSThomas Huth } 1769372122e3SRichard Henderson 1770372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1771372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1772372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1773372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1774372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1775372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1776372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1777372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1778372122e3SRichard Henderson }; 1779372122e3SRichard Henderson 1780372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1781372122e3SRichard Henderson { 1782372122e3SRichard Henderson DisasContext dc; 1783372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 1784fcf5ef2aSThomas Huth } 1785fcf5ef2aSThomas Huth 178690c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1787fcf5ef2aSThomas Huth { 1788fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1789fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 1790fcf5ef2aSThomas Huth int i; 1791fcf5ef2aSThomas Huth 179290c84c56SMarkus Armbruster if (!env) { 1793fcf5ef2aSThomas Huth return; 179490c84c56SMarkus Armbruster } 1795fcf5ef2aSThomas Huth 17960f96e96bSRichard Henderson qemu_fprintf(f, "IN: PC=%x %s\n", 179776e8187dSRichard Henderson env->pc, lookup_symbol(env->pc)); 17986efd5599SRichard Henderson qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " 1799eb2022b7SRichard Henderson "imm=%x iflags=%x fsr=%x rbtr=%x\n", 180078e9caf2SRichard Henderson env->msr, env->esr, env->ear, 1801eb2022b7SRichard Henderson env->imm, env->iflags, env->fsr, env->btr); 18020f96e96bSRichard Henderson qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 1803fcf5ef2aSThomas Huth env->btaken, env->btarget, 18042e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18052e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18062e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18072e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18082ead1b18SJoe Komlodi for (i = 0; i < 12; i++) { 18092ead1b18SJoe Komlodi qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); 18102ead1b18SJoe Komlodi if ((i + 1) % 4 == 0) { 18112ead1b18SJoe Komlodi qemu_fprintf(f, "\n"); 18122ead1b18SJoe Komlodi } 18132ead1b18SJoe Komlodi } 1814fcf5ef2aSThomas Huth 18152ead1b18SJoe Komlodi /* Registers that aren't modeled are reported as 0 */ 181639db007eSRichard Henderson qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " 1817af20a93aSRichard Henderson "rtlblo=0 rtlbhi=0\n", env->edr); 18182ead1b18SJoe Komlodi qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); 1819fcf5ef2aSThomas Huth for (i = 0; i < 32; i++) { 182090c84c56SMarkus Armbruster qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); 1821fcf5ef2aSThomas Huth if ((i + 1) % 4 == 0) 182290c84c56SMarkus Armbruster qemu_fprintf(f, "\n"); 1823fcf5ef2aSThomas Huth } 182490c84c56SMarkus Armbruster qemu_fprintf(f, "\n\n"); 1825fcf5ef2aSThomas Huth } 1826fcf5ef2aSThomas Huth 1827fcf5ef2aSThomas Huth void mb_tcg_init(void) 1828fcf5ef2aSThomas Huth { 1829480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1830480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1831fcf5ef2aSThomas Huth 1832480d29a8SRichard Henderson static const struct { 1833480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1834480d29a8SRichard Henderson } i32s[] = { 1835480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1836480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1837480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1838480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1839480d29a8SRichard Henderson 1840480d29a8SRichard Henderson SP(pc), 1841480d29a8SRichard Henderson SP(msr), 18421074c0fbSRichard Henderson SP(msr_c), 1843480d29a8SRichard Henderson SP(imm), 1844480d29a8SRichard Henderson SP(iflags), 1845480d29a8SRichard Henderson SP(btaken), 1846480d29a8SRichard Henderson SP(btarget), 1847480d29a8SRichard Henderson SP(res_val), 1848480d29a8SRichard Henderson }; 1849480d29a8SRichard Henderson 1850480d29a8SRichard Henderson #undef R 1851480d29a8SRichard Henderson #undef SP 1852480d29a8SRichard Henderson 1853480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1854480d29a8SRichard Henderson *i32s[i].var = 1855480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1856fcf5ef2aSThomas Huth } 185776e8187dSRichard Henderson 1858480d29a8SRichard Henderson cpu_res_addr = 1859480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1860fcf5ef2aSThomas Huth } 1861fcf5ef2aSThomas Huth 1862fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1863fcf5ef2aSThomas Huth target_ulong *data) 1864fcf5ef2aSThomas Huth { 186576e8187dSRichard Henderson env->pc = data[0]; 1866fcf5ef2aSThomas Huth } 1867