1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * Xilinx MicroBlaze emulation for qemu: main translation routines. 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2009 Edgar E. Iglesias. 5fcf5ef2aSThomas Huth * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 6fcf5ef2aSThomas Huth * 7fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or 8fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public 9fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either 10fcf5ef2aSThomas Huth * version 2 of the License, or (at your option) any later version. 11fcf5ef2aSThomas Huth * 12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fcf5ef2aSThomas Huth * Lesser General Public License for more details. 16fcf5ef2aSThomas Huth * 17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fcf5ef2aSThomas Huth */ 20fcf5ef2aSThomas Huth 21fcf5ef2aSThomas Huth #include "qemu/osdep.h" 22fcf5ef2aSThomas Huth #include "cpu.h" 23fcf5ef2aSThomas Huth #include "disas/disas.h" 24fcf5ef2aSThomas Huth #include "exec/exec-all.h" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 26fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 27fcf5ef2aSThomas Huth #include "microblaze-decode.h" 28fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h" 29fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 3077fc6f5eSLluís Vilanova #include "exec/translator.h" 3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 32fcf5ef2aSThomas Huth 33fcf5ef2aSThomas Huth #include "trace-tcg.h" 34fcf5ef2aSThomas Huth #include "exec/log.h" 35fcf5ef2aSThomas Huth 36fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 37fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 38fcf5ef2aSThomas Huth 3977fc6f5eSLluís Vilanova /* is_jmp field values */ 4077fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 4177fc6f5eSLluís Vilanova #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ 4277fc6f5eSLluís Vilanova 43cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 440f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 453e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 461074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 479b158558SRichard Henderson static TCGv_i32 cpu_imm; 489b158558SRichard Henderson static TCGv_i32 cpu_btaken; 490f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 509b158558SRichard Henderson static TCGv_i32 cpu_iflags; 519b158558SRichard Henderson static TCGv cpu_res_addr; 529b158558SRichard Henderson static TCGv_i32 cpu_res_val; 53fcf5ef2aSThomas Huth 54fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 55fcf5ef2aSThomas Huth 56fcf5ef2aSThomas Huth /* This is the state at translation time. */ 57fcf5ef2aSThomas Huth typedef struct DisasContext { 58d4705ae0SRichard Henderson DisasContextBase base; 59fcf5ef2aSThomas Huth MicroBlazeCPU *cpu; 60fcf5ef2aSThomas Huth 6120800179SRichard Henderson TCGv_i32 r0; 6220800179SRichard Henderson bool r0_set; 6320800179SRichard Henderson 64fcf5ef2aSThomas Huth /* Decoder. */ 65fcf5ef2aSThomas Huth int type_b; 66fcf5ef2aSThomas Huth uint32_t ir; 67d7ecb757SRichard Henderson uint32_t ext_imm; 68fcf5ef2aSThomas Huth uint8_t opcode; 69fcf5ef2aSThomas Huth uint8_t rd, ra, rb; 70fcf5ef2aSThomas Huth uint16_t imm; 71fcf5ef2aSThomas Huth 72fcf5ef2aSThomas Huth unsigned int cpustate_changed; 73fcf5ef2aSThomas Huth unsigned int delayed_branch; 74fcf5ef2aSThomas Huth unsigned int tb_flags, synced_flags; /* tb dependent flags. */ 75fcf5ef2aSThomas Huth unsigned int clear_imm; 76fcf5ef2aSThomas Huth 77fcf5ef2aSThomas Huth #define JMP_NOJMP 0 78fcf5ef2aSThomas Huth #define JMP_DIRECT 1 79fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2 80fcf5ef2aSThomas Huth #define JMP_INDIRECT 3 81fcf5ef2aSThomas Huth unsigned int jmp; 82fcf5ef2aSThomas Huth uint32_t jmp_pc; 83fcf5ef2aSThomas Huth 84fcf5ef2aSThomas Huth int abort_at_next_insn; 85fcf5ef2aSThomas Huth } DisasContext; 86fcf5ef2aSThomas Huth 8720800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8820800179SRichard Henderson { 8920800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 9020800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 9120800179SRichard Henderson } 9220800179SRichard Henderson return x; 9320800179SRichard Henderson } 9420800179SRichard Henderson 9544d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9644d1432bSRichard Henderson #include "decode-insns.c.inc" 9744d1432bSRichard Henderson 98fcf5ef2aSThomas Huth static inline void t_sync_flags(DisasContext *dc) 99fcf5ef2aSThomas Huth { 100fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 101fcf5ef2aSThomas Huth if (dc->tb_flags != dc->synced_flags) { 1029b158558SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags); 103fcf5ef2aSThomas Huth dc->synced_flags = dc->tb_flags; 104fcf5ef2aSThomas Huth } 105fcf5ef2aSThomas Huth } 106fcf5ef2aSThomas Huth 10741ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 108fcf5ef2aSThomas Huth { 109fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 110fcf5ef2aSThomas Huth 111fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 112fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 113d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 114fcf5ef2aSThomas Huth } 115fcf5ef2aSThomas Huth 11641ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11741ba37c4SRichard Henderson { 11841ba37c4SRichard Henderson t_sync_flags(dc); 119d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 12041ba37c4SRichard Henderson gen_raise_exception(dc, index); 12141ba37c4SRichard Henderson } 12241ba37c4SRichard Henderson 12341ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12441ba37c4SRichard Henderson { 12541ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12641ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12741ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12841ba37c4SRichard Henderson 12941ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 13041ba37c4SRichard Henderson } 13141ba37c4SRichard Henderson 132fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 133fcf5ef2aSThomas Huth { 134fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 135d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 136fcf5ef2aSThomas Huth #else 137fcf5ef2aSThomas Huth return true; 138fcf5ef2aSThomas Huth #endif 139fcf5ef2aSThomas Huth } 140fcf5ef2aSThomas Huth 141fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 142fcf5ef2aSThomas Huth { 143d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1440b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1450b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1460b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1470b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1480b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 149fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1500f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 151d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 152fcf5ef2aSThomas Huth } else { 1530f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 15407ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 155fcf5ef2aSThomas Huth } 156d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 157fcf5ef2aSThomas Huth } 158fcf5ef2aSThomas Huth 159bdfc1e88SEdgar E. Iglesias /* 1609ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1619ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1629ba8cd45SEdgar E. Iglesias */ 1639ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1649ba8cd45SEdgar E. Iglesias { 1659ba8cd45SEdgar E. Iglesias if (cond && (dc->tb_flags & MSR_EE_FLAG) 1665143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 16741ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1689ba8cd45SEdgar E. Iglesias } 1699ba8cd45SEdgar E. Iglesias return cond; 1709ba8cd45SEdgar E. Iglesias } 1719ba8cd45SEdgar E. Iglesias 1729ba8cd45SEdgar E. Iglesias /* 173bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 174bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 175bdfc1e88SEdgar E. Iglesias */ 176bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 177bdfc1e88SEdgar E. Iglesias { 178bdfc1e88SEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 179bdfc1e88SEdgar E. Iglesias bool cond_user = cond && mem_index == MMU_USER_IDX; 180bdfc1e88SEdgar E. Iglesias 181bdfc1e88SEdgar E. Iglesias if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { 18241ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 183bdfc1e88SEdgar E. Iglesias } 184bdfc1e88SEdgar E. Iglesias return cond_user; 185bdfc1e88SEdgar E. Iglesias } 186bdfc1e88SEdgar E. Iglesias 187d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc) 188fcf5ef2aSThomas Huth { 189d7ecb757SRichard Henderson tcg_debug_assert(dc->type_b); 19020800179SRichard Henderson return typeb_imm(dc, (int16_t)dc->imm); 191fcf5ef2aSThomas Huth } 192fcf5ef2aSThomas Huth 193cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) 194fcf5ef2aSThomas Huth { 195fcf5ef2aSThomas Huth if (dc->type_b) { 196d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc)); 1979b158558SRichard Henderson return &cpu_imm; 198d7ecb757SRichard Henderson } 199fcf5ef2aSThomas Huth return &cpu_R[dc->rb]; 200fcf5ef2aSThomas Huth } 201fcf5ef2aSThomas Huth 20220800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 203fcf5ef2aSThomas Huth { 20420800179SRichard Henderson if (likely(reg != 0)) { 20520800179SRichard Henderson return cpu_R[reg]; 206fcf5ef2aSThomas Huth } 20720800179SRichard Henderson if (!dc->r0_set) { 20820800179SRichard Henderson if (dc->r0 == NULL) { 20920800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 210fcf5ef2aSThomas Huth } 21120800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 21220800179SRichard Henderson dc->r0_set = true; 21320800179SRichard Henderson } 21420800179SRichard Henderson return dc->r0; 215fcf5ef2aSThomas Huth } 216fcf5ef2aSThomas Huth 21720800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 21820800179SRichard Henderson { 21920800179SRichard Henderson if (likely(reg != 0)) { 22020800179SRichard Henderson return cpu_R[reg]; 22120800179SRichard Henderson } 22220800179SRichard Henderson if (dc->r0 == NULL) { 22320800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 22420800179SRichard Henderson } 22520800179SRichard Henderson return dc->r0; 226fcf5ef2aSThomas Huth } 227fcf5ef2aSThomas Huth 22820800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 22920800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 23020800179SRichard Henderson { 23120800179SRichard Henderson TCGv_i32 rd, ra, rb; 23220800179SRichard Henderson 23320800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 23420800179SRichard Henderson return true; 235fcf5ef2aSThomas Huth } 23620800179SRichard Henderson 23720800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 23820800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 23920800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 24020800179SRichard Henderson fn(rd, ra, rb); 24120800179SRichard Henderson return true; 24220800179SRichard Henderson } 24320800179SRichard Henderson 24439cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, 24539cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32)) 24639cf3864SRichard Henderson { 24739cf3864SRichard Henderson TCGv_i32 rd, ra; 24839cf3864SRichard Henderson 24939cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) { 25039cf3864SRichard Henderson return true; 25139cf3864SRichard Henderson } 25239cf3864SRichard Henderson 25339cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd); 25439cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra); 25539cf3864SRichard Henderson fn(rd, ra); 25639cf3864SRichard Henderson return true; 25739cf3864SRichard Henderson } 25839cf3864SRichard Henderson 25920800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 26020800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 26120800179SRichard Henderson { 26220800179SRichard Henderson TCGv_i32 rd, ra; 26320800179SRichard Henderson 26420800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 26520800179SRichard Henderson return true; 26620800179SRichard Henderson } 26720800179SRichard Henderson 26820800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 26920800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 27020800179SRichard Henderson fni(rd, ra, arg->imm); 27120800179SRichard Henderson return true; 27220800179SRichard Henderson } 27320800179SRichard Henderson 27420800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 27520800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 27620800179SRichard Henderson { 27720800179SRichard Henderson TCGv_i32 rd, ra, imm; 27820800179SRichard Henderson 27920800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 28020800179SRichard Henderson return true; 28120800179SRichard Henderson } 28220800179SRichard Henderson 28320800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 28420800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 28520800179SRichard Henderson imm = tcg_const_i32(arg->imm); 28620800179SRichard Henderson 28720800179SRichard Henderson fn(rd, ra, imm); 28820800179SRichard Henderson 28920800179SRichard Henderson tcg_temp_free_i32(imm); 29020800179SRichard Henderson return true; 29120800179SRichard Henderson } 29220800179SRichard Henderson 29320800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 29420800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 29520800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 29620800179SRichard Henderson 297607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 298607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 299607f5767SRichard Henderson { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } 300607f5767SRichard Henderson 30139cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 30239cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 30339cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 30439cf3864SRichard Henderson 30539cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 30639cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 30739cf3864SRichard Henderson { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); } 30839cf3864SRichard Henderson 30920800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 31020800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 31120800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 31220800179SRichard Henderson 31397955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 31497955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 31597955cebSRichard Henderson { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } 31697955cebSRichard Henderson 31720800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 31820800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 31920800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 32020800179SRichard Henderson 32120800179SRichard Henderson /* No input carry, but output carry. */ 32220800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 32320800179SRichard Henderson { 32420800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 32520800179SRichard Henderson 32620800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 32720800179SRichard Henderson 32820800179SRichard Henderson tcg_temp_free_i32(zero); 32920800179SRichard Henderson } 33020800179SRichard Henderson 33120800179SRichard Henderson /* Input and output carry. */ 33220800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 33320800179SRichard Henderson { 33420800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 33520800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 33620800179SRichard Henderson 33720800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 33820800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 33920800179SRichard Henderson 34020800179SRichard Henderson tcg_temp_free_i32(tmp); 34120800179SRichard Henderson tcg_temp_free_i32(zero); 34220800179SRichard Henderson } 34320800179SRichard Henderson 34420800179SRichard Henderson /* Input carry, but no output carry. */ 34520800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 34620800179SRichard Henderson { 34720800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 34820800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 34920800179SRichard Henderson } 35020800179SRichard Henderson 35120800179SRichard Henderson DO_TYPEA(add, true, gen_add) 35220800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 35320800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 35420800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 35520800179SRichard Henderson 35620800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 35720800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 35820800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 35920800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 36020800179SRichard Henderson 361cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 362cb0a0a4cSRichard Henderson { 363cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 364cb0a0a4cSRichard Henderson } 365cb0a0a4cSRichard Henderson 366cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 367cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 368cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 369cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 370cb0a0a4cSRichard Henderson 371*081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 372*081d8e02SRichard Henderson { 373*081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 374*081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 375*081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 376*081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 377*081d8e02SRichard Henderson } 378*081d8e02SRichard Henderson 379*081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 380*081d8e02SRichard Henderson { 381*081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 382*081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 383*081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 384*081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 385*081d8e02SRichard Henderson } 386*081d8e02SRichard Henderson 387*081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 388*081d8e02SRichard Henderson { 389*081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 390*081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 391*081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 392*081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 393*081d8e02SRichard Henderson } 394*081d8e02SRichard Henderson 395*081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 396*081d8e02SRichard Henderson { 397*081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 398*081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 399*081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 400*081d8e02SRichard Henderson 401*081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 402*081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 403*081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 404*081d8e02SRichard Henderson imm_w, imm_s); 405*081d8e02SRichard Henderson } else { 406*081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 407*081d8e02SRichard Henderson } 408*081d8e02SRichard Henderson } 409*081d8e02SRichard Henderson 410*081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 411*081d8e02SRichard Henderson { 412*081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 413*081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 414*081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 415*081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 416*081d8e02SRichard Henderson 417*081d8e02SRichard Henderson if (imm_w < imm_s) { 418*081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 419*081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 420*081d8e02SRichard Henderson imm_w, imm_s); 421*081d8e02SRichard Henderson } else { 422*081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 423*081d8e02SRichard Henderson } 424*081d8e02SRichard Henderson } 425*081d8e02SRichard Henderson 426*081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 427*081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 428*081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 429*081d8e02SRichard Henderson 430*081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 431*081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 432*081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 433*081d8e02SRichard Henderson 434*081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 435*081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 436*081d8e02SRichard Henderson 43739cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 43839cf3864SRichard Henderson { 43939cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 44039cf3864SRichard Henderson } 44139cf3864SRichard Henderson 44239cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 44339cf3864SRichard Henderson 44458b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 44558b48b63SRichard Henderson { 44658b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 44758b48b63SRichard Henderson 44858b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 44958b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 45058b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 45158b48b63SRichard Henderson tcg_temp_free_i32(lt); 45258b48b63SRichard Henderson } 45358b48b63SRichard Henderson 45458b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 45558b48b63SRichard Henderson { 45658b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 45758b48b63SRichard Henderson 45858b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 45958b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 46058b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 46158b48b63SRichard Henderson tcg_temp_free_i32(lt); 46258b48b63SRichard Henderson } 46358b48b63SRichard Henderson 46458b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 46558b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 466a2b0b90eSRichard Henderson 467b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 468b1354342SRichard Henderson { 469b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 470b1354342SRichard Henderson } 471b1354342SRichard Henderson 472b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 473b1354342SRichard Henderson { 474b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 475b1354342SRichard Henderson } 476b1354342SRichard Henderson 477b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 478b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 479b1354342SRichard Henderson 48097955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 48197955cebSRichard Henderson { 48297955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 48397955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 48497955cebSRichard Henderson tcg_temp_free_i32(tmp); 48597955cebSRichard Henderson } 48697955cebSRichard Henderson 48797955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 48897955cebSRichard Henderson { 48997955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 49097955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 49197955cebSRichard Henderson tcg_temp_free_i32(tmp); 49297955cebSRichard Henderson } 49397955cebSRichard Henderson 49497955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 49597955cebSRichard Henderson { 49697955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 49797955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 49897955cebSRichard Henderson tcg_temp_free_i32(tmp); 49997955cebSRichard Henderson } 50097955cebSRichard Henderson 50197955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 50297955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 50397955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 50497955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 50597955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 50697955cebSRichard Henderson 507cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 508cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 509cb0a0a4cSRichard Henderson 510607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 511607f5767SRichard Henderson { 512607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 513607f5767SRichard Henderson } 514607f5767SRichard Henderson 515607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 516607f5767SRichard Henderson { 517607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 518607f5767SRichard Henderson } 519607f5767SRichard Henderson 520607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 521607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 522607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 523607f5767SRichard Henderson 524a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 525a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 526a2b0b90eSRichard Henderson { 527a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 528a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 529a2b0b90eSRichard Henderson } 530a2b0b90eSRichard Henderson 531a2b0b90eSRichard Henderson /* Input and output carry. */ 532a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 533a2b0b90eSRichard Henderson { 534a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 535a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 536a2b0b90eSRichard Henderson 537a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 538a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 539a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 540a2b0b90eSRichard Henderson 541a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 542a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 543a2b0b90eSRichard Henderson } 544a2b0b90eSRichard Henderson 545a2b0b90eSRichard Henderson /* No input or output carry. */ 546a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 547a2b0b90eSRichard Henderson { 548a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 549a2b0b90eSRichard Henderson } 550a2b0b90eSRichard Henderson 551a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 552a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 553a2b0b90eSRichard Henderson { 554a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 555a2b0b90eSRichard Henderson 556a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 557a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 558a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 559a2b0b90eSRichard Henderson 560a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 561a2b0b90eSRichard Henderson } 562a2b0b90eSRichard Henderson 563a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 564a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 565a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 566a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 567a2b0b90eSRichard Henderson 568a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 569a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 570a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 571a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 572a2b0b90eSRichard Henderson 57339cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 57439cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 57539cf3864SRichard Henderson 57639cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 57739cf3864SRichard Henderson { 57839cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 57939cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 58039cf3864SRichard Henderson } 58139cf3864SRichard Henderson 58239cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 58339cf3864SRichard Henderson { 58439cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 58539cf3864SRichard Henderson 58639cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 58739cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 58839cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 58939cf3864SRichard Henderson 59039cf3864SRichard Henderson tcg_temp_free_i32(tmp); 59139cf3864SRichard Henderson } 59239cf3864SRichard Henderson 59339cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 59439cf3864SRichard Henderson { 59539cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 59639cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 59739cf3864SRichard Henderson } 59839cf3864SRichard Henderson 59939cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 60039cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 60139cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 60239cf3864SRichard Henderson 60339cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 60439cf3864SRichard Henderson { 60539cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 60639cf3864SRichard Henderson } 60739cf3864SRichard Henderson 60839cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 60939cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 61039cf3864SRichard Henderson 61139cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 61239cf3864SRichard Henderson { 61339cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 61439cf3864SRichard Henderson trap_userspace(dc, true); 61539cf3864SRichard Henderson return true; 61639cf3864SRichard Henderson } 61739cf3864SRichard Henderson 618cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 619cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 620cb0a0a4cSRichard Henderson 62120800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 62220800179SRichard Henderson { 62320800179SRichard Henderson /* If opcode_0_illegal, trap. */ 62420800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 62520800179SRichard Henderson trap_illegal(dc, true); 62620800179SRichard Henderson return true; 62720800179SRichard Henderson } 62820800179SRichard Henderson /* 62920800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 63020800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 63120800179SRichard Henderson */ 63220800179SRichard Henderson return false; 633fcf5ef2aSThomas Huth } 634fcf5ef2aSThomas Huth 6351074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 636fcf5ef2aSThomas Huth { 6371074c0fbSRichard Henderson TCGv_i32 t; 6381074c0fbSRichard Henderson 6391074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 6401074c0fbSRichard Henderson t = tcg_temp_new_i32(); 6411074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 6421074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 6431074c0fbSRichard Henderson tcg_temp_free_i32(t); 644fcf5ef2aSThomas Huth } 645fcf5ef2aSThomas Huth 6461074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 647fcf5ef2aSThomas Huth { 648fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 6491074c0fbSRichard Henderson 6501074c0fbSRichard Henderson /* Install MSR_C. */ 6511074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 6521074c0fbSRichard Henderson 6531074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 6541074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 655fcf5ef2aSThomas Huth } 656fcf5ef2aSThomas Huth 657fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc) 658fcf5ef2aSThomas Huth { 659fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 660cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 6612023e9a3SEdgar E. Iglesias unsigned int sr, rn; 662f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 663fcf5ef2aSThomas Huth 6642023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 6652023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 6662023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 667fcf5ef2aSThomas Huth dc->type_b = 1; 6682023e9a3SEdgar E. Iglesias if (to) { 669fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 670f0f7e7f7SEdgar E. Iglesias } 671f0f7e7f7SEdgar E. Iglesias 672f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 673f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 674f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 675f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 676f0f7e7f7SEdgar E. Iglesias 677f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 6782023e9a3SEdgar E. Iglesias } 679fcf5ef2aSThomas Huth 680fcf5ef2aSThomas Huth /* msrclr and msrset. */ 6812023e9a3SEdgar E. Iglesias if (clrset) { 6822023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 683fcf5ef2aSThomas Huth 68456837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 685fcf5ef2aSThomas Huth /* nop??? */ 686fcf5ef2aSThomas Huth return; 687fcf5ef2aSThomas Huth } 688fcf5ef2aSThomas Huth 689bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 690fcf5ef2aSThomas Huth return; 691fcf5ef2aSThomas Huth } 692fcf5ef2aSThomas Huth 693fcf5ef2aSThomas Huth if (dc->rd) 694fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 695fcf5ef2aSThomas Huth 696cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 697cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 698fcf5ef2aSThomas Huth msr_read(dc, t0); 699cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 700fcf5ef2aSThomas Huth 701fcf5ef2aSThomas Huth if (clr) { 702cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 703cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 704fcf5ef2aSThomas Huth } else 705cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 706fcf5ef2aSThomas Huth msr_write(dc, t0); 707cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 708cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 709d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 710d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 711fcf5ef2aSThomas Huth return; 712fcf5ef2aSThomas Huth } 713fcf5ef2aSThomas Huth 714bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 715fcf5ef2aSThomas Huth return; 716fcf5ef2aSThomas Huth } 717fcf5ef2aSThomas Huth 718fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 719fcf5ef2aSThomas Huth /* Catch read/writes to the mmu block. */ 720fcf5ef2aSThomas Huth if ((sr & ~0xff) == 0x1000) { 721f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 72205a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 72305a9a651SEdgar E. Iglesias 724fcf5ef2aSThomas Huth sr &= 7; 72505a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 72605a9a651SEdgar E. Iglesias if (to) { 727f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 72805a9a651SEdgar E. Iglesias } else { 729f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 73005a9a651SEdgar E. Iglesias } 73105a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 732f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 733fcf5ef2aSThomas Huth return; 734fcf5ef2aSThomas Huth } 735fcf5ef2aSThomas Huth #endif 736fcf5ef2aSThomas Huth 737fcf5ef2aSThomas Huth if (to) { 738fcf5ef2aSThomas Huth switch (sr) { 739aa28e6d4SRichard Henderson case SR_PC: 740fcf5ef2aSThomas Huth break; 741aa28e6d4SRichard Henderson case SR_MSR: 742fcf5ef2aSThomas Huth msr_write(dc, cpu_R[dc->ra]); 743fcf5ef2aSThomas Huth break; 744351527b7SEdgar E. Iglesias case SR_EAR: 745dbdb77c4SRichard Henderson { 746dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 747dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 748dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 749dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 750dbdb77c4SRichard Henderson } 751aa28e6d4SRichard Henderson break; 752351527b7SEdgar E. Iglesias case SR_ESR: 75341ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 75441ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 755aa28e6d4SRichard Henderson break; 756ab6dd380SEdgar E. Iglesias case SR_FSR: 75786017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 75886017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 759aa28e6d4SRichard Henderson break; 760aa28e6d4SRichard Henderson case SR_BTR: 761ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 762ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 763aa28e6d4SRichard Henderson break; 764aa28e6d4SRichard Henderson case SR_EDR: 76539db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 76639db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 767fcf5ef2aSThomas Huth break; 768fcf5ef2aSThomas Huth case 0x800: 769cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 770cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 771fcf5ef2aSThomas Huth break; 772fcf5ef2aSThomas Huth case 0x802: 773cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 774cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 775fcf5ef2aSThomas Huth break; 776fcf5ef2aSThomas Huth default: 777fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 778fcf5ef2aSThomas Huth break; 779fcf5ef2aSThomas Huth } 780fcf5ef2aSThomas Huth } else { 781fcf5ef2aSThomas Huth switch (sr) { 782aa28e6d4SRichard Henderson case SR_PC: 783d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 784fcf5ef2aSThomas Huth break; 785aa28e6d4SRichard Henderson case SR_MSR: 786fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 787fcf5ef2aSThomas Huth break; 788351527b7SEdgar E. Iglesias case SR_EAR: 789dbdb77c4SRichard Henderson { 790dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 791dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 792a1b48e3aSEdgar E. Iglesias if (extended) { 793dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 794aa28e6d4SRichard Henderson } else { 795dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 796dbdb77c4SRichard Henderson } 797dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 798a1b48e3aSEdgar E. Iglesias } 799aa28e6d4SRichard Henderson break; 800351527b7SEdgar E. Iglesias case SR_ESR: 80141ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 80241ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 803aa28e6d4SRichard Henderson break; 804351527b7SEdgar E. Iglesias case SR_FSR: 80586017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 80686017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 807aa28e6d4SRichard Henderson break; 808351527b7SEdgar E. Iglesias case SR_BTR: 809ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 810ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 811aa28e6d4SRichard Henderson break; 8127cdae31dSTong Ho case SR_EDR: 81339db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 81439db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 815fcf5ef2aSThomas Huth break; 816fcf5ef2aSThomas Huth case 0x800: 817cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 818cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 819fcf5ef2aSThomas Huth break; 820fcf5ef2aSThomas Huth case 0x802: 821cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 822cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 823fcf5ef2aSThomas Huth break; 824351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 825fcf5ef2aSThomas Huth rn = sr & 0xf; 826cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 827fcf5ef2aSThomas Huth cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 828fcf5ef2aSThomas Huth break; 829fcf5ef2aSThomas Huth default: 830fcf5ef2aSThomas Huth cpu_abort(cs, "unknown mfs reg %x\n", sr); 831fcf5ef2aSThomas Huth break; 832fcf5ef2aSThomas Huth } 833fcf5ef2aSThomas Huth } 834fcf5ef2aSThomas Huth 835fcf5ef2aSThomas Huth if (dc->rd == 0) { 836cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 837fcf5ef2aSThomas Huth } 838fcf5ef2aSThomas Huth } 839fcf5ef2aSThomas Huth 840fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc) 841fcf5ef2aSThomas Huth { 842fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 843fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT) { 8449b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 845fcf5ef2aSThomas Huth } 846fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 8470f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 848fcf5ef2aSThomas Huth } 849fcf5ef2aSThomas Huth } 850fcf5ef2aSThomas Huth 851fcf5ef2aSThomas Huth static void dec_imm(DisasContext *dc) 852fcf5ef2aSThomas Huth { 853d7ecb757SRichard Henderson dc->ext_imm = dc->imm << 16; 854d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 855fcf5ef2aSThomas Huth dc->tb_flags |= IMM_FLAG; 856fcf5ef2aSThomas Huth dc->clear_imm = 0; 857fcf5ef2aSThomas Huth } 858fcf5ef2aSThomas Huth 859d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) 860fcf5ef2aSThomas Huth { 8610e9033c8SEdgar E. Iglesias /* Should be set to true if r1 is used by loadstores. */ 8620e9033c8SEdgar E. Iglesias bool stackprot = false; 863403322eaSEdgar E. Iglesias TCGv_i32 t32; 864fcf5ef2aSThomas Huth 865fcf5ef2aSThomas Huth /* All load/stores use ra. */ 866fcf5ef2aSThomas Huth if (dc->ra == 1 && dc->cpu->cfg.stackprot) { 8670e9033c8SEdgar E. Iglesias stackprot = true; 868fcf5ef2aSThomas Huth } 869fcf5ef2aSThomas Huth 870fcf5ef2aSThomas Huth /* Treat the common cases first. */ 871fcf5ef2aSThomas Huth if (!dc->type_b) { 872d248e1beSEdgar E. Iglesias if (ea) { 873d248e1beSEdgar E. Iglesias int addr_size = dc->cpu->cfg.addr_size; 874d248e1beSEdgar E. Iglesias 875d248e1beSEdgar E. Iglesias if (addr_size == 32) { 876d248e1beSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 877d248e1beSEdgar E. Iglesias return; 878d248e1beSEdgar E. Iglesias } 879d248e1beSEdgar E. Iglesias 880d248e1beSEdgar E. Iglesias tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]); 881d248e1beSEdgar E. Iglesias if (addr_size < 64) { 882d248e1beSEdgar E. Iglesias /* Mask off out of range bits. */ 883d248e1beSEdgar E. Iglesias tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size)); 884d248e1beSEdgar E. Iglesias } 885d248e1beSEdgar E. Iglesias return; 886d248e1beSEdgar E. Iglesias } 887d248e1beSEdgar E. Iglesias 8880dc4af5cSEdgar E. Iglesias /* If any of the regs is r0, set t to the value of the other reg. */ 889fcf5ef2aSThomas Huth if (dc->ra == 0) { 890403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 8910dc4af5cSEdgar E. Iglesias return; 892fcf5ef2aSThomas Huth } else if (dc->rb == 0) { 893403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]); 8940dc4af5cSEdgar E. Iglesias return; 895fcf5ef2aSThomas Huth } 896fcf5ef2aSThomas Huth 897fcf5ef2aSThomas Huth if (dc->rb == 1 && dc->cpu->cfg.stackprot) { 8980e9033c8SEdgar E. Iglesias stackprot = true; 899fcf5ef2aSThomas Huth } 900fcf5ef2aSThomas Huth 901403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 902403322eaSEdgar E. Iglesias tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]); 903403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 904403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 905fcf5ef2aSThomas Huth 906fcf5ef2aSThomas Huth if (stackprot) { 9070a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 908fcf5ef2aSThomas Huth } 9090dc4af5cSEdgar E. Iglesias return; 910fcf5ef2aSThomas Huth } 911fcf5ef2aSThomas Huth /* Immediate. */ 912403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 913d7ecb757SRichard Henderson tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc)); 914403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 915403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 916fcf5ef2aSThomas Huth 917fcf5ef2aSThomas Huth if (stackprot) { 9180a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 919fcf5ef2aSThomas Huth } 9200dc4af5cSEdgar E. Iglesias return; 921fcf5ef2aSThomas Huth } 922fcf5ef2aSThomas Huth 923fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc) 924fcf5ef2aSThomas Huth { 925403322eaSEdgar E. Iglesias TCGv_i32 v; 926403322eaSEdgar E. Iglesias TCGv addr; 9278534063aSEdgar E. Iglesias unsigned int size; 928d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 929d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 93014776ab5STony Nguyen MemOp mop; 931fcf5ef2aSThomas Huth 932fcf5ef2aSThomas Huth mop = dc->opcode & 3; 933fcf5ef2aSThomas Huth size = 1 << mop; 934fcf5ef2aSThomas Huth if (!dc->type_b) { 935d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 9368534063aSEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 9378534063aSEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 938fcf5ef2aSThomas Huth } 939fcf5ef2aSThomas Huth mop |= MO_TE; 940fcf5ef2aSThomas Huth if (rev) { 941fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 942fcf5ef2aSThomas Huth } 943fcf5ef2aSThomas Huth 9449ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 945fcf5ef2aSThomas Huth return; 946fcf5ef2aSThomas Huth } 947fcf5ef2aSThomas Huth 948d248e1beSEdgar E. Iglesias if (trap_userspace(dc, ea)) { 949d248e1beSEdgar E. Iglesias return; 950d248e1beSEdgar E. Iglesias } 951d248e1beSEdgar E. Iglesias 952fcf5ef2aSThomas Huth t_sync_flags(dc); 953403322eaSEdgar E. Iglesias addr = tcg_temp_new(); 954d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 955d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 956d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 957fcf5ef2aSThomas Huth 958fcf5ef2aSThomas Huth /* 959fcf5ef2aSThomas Huth * When doing reverse accesses we need to do two things. 960fcf5ef2aSThomas Huth * 961fcf5ef2aSThomas Huth * 1. Reverse the address wrt endianness. 962fcf5ef2aSThomas Huth * 2. Byteswap the data lanes on the way back into the CPU core. 963fcf5ef2aSThomas Huth */ 964fcf5ef2aSThomas Huth if (rev && size != 4) { 965fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 966fcf5ef2aSThomas Huth switch (size) { 967fcf5ef2aSThomas Huth case 1: 968fcf5ef2aSThomas Huth { 969a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 970fcf5ef2aSThomas Huth break; 971fcf5ef2aSThomas Huth } 972fcf5ef2aSThomas Huth 973fcf5ef2aSThomas Huth case 2: 974fcf5ef2aSThomas Huth /* 00 -> 10 975fcf5ef2aSThomas Huth 10 -> 00. */ 976403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 977fcf5ef2aSThomas Huth break; 978fcf5ef2aSThomas Huth default: 979fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 980fcf5ef2aSThomas Huth break; 981fcf5ef2aSThomas Huth } 982fcf5ef2aSThomas Huth } 983fcf5ef2aSThomas Huth 984fcf5ef2aSThomas Huth /* lwx does not throw unaligned access errors, so force alignment */ 985fcf5ef2aSThomas Huth if (ex) { 986403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 987fcf5ef2aSThomas Huth } 988fcf5ef2aSThomas Huth 989fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 990fcf5ef2aSThomas Huth sync_jmpstate(dc); 991fcf5ef2aSThomas Huth 992fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 993fcf5ef2aSThomas Huth /* 994fcf5ef2aSThomas Huth * Microblaze gives MMU faults priority over faults due to 995fcf5ef2aSThomas Huth * unaligned addresses. That's why we speculatively do the load 996fcf5ef2aSThomas Huth * into v. If the load succeeds, we verify alignment of the 997fcf5ef2aSThomas Huth * address and if that succeeds we write into the destination reg. 998fcf5ef2aSThomas Huth */ 999cfeea807SEdgar E. Iglesias v = tcg_temp_new_i32(); 1000d248e1beSEdgar E. Iglesias tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); 1001fcf5ef2aSThomas Huth 10021507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1003a6338015SEdgar E. Iglesias TCGv_i32 t0 = tcg_const_i32(0); 1004a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1005a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1006a6338015SEdgar E. Iglesias 1007d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1008a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t0, tsize); 1009a6338015SEdgar E. Iglesias 1010a6338015SEdgar E. Iglesias tcg_temp_free_i32(t0); 1011a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1012a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1013fcf5ef2aSThomas Huth } 1014fcf5ef2aSThomas Huth 1015fcf5ef2aSThomas Huth if (ex) { 10169b158558SRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 10179b158558SRichard Henderson tcg_gen_mov_i32(cpu_res_val, v); 1018fcf5ef2aSThomas Huth } 1019fcf5ef2aSThomas Huth if (dc->rd) { 1020cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(cpu_R[dc->rd], v); 1021fcf5ef2aSThomas Huth } 1022cfeea807SEdgar E. Iglesias tcg_temp_free_i32(v); 1023fcf5ef2aSThomas Huth 1024fcf5ef2aSThomas Huth if (ex) { /* lwx */ 1025fcf5ef2aSThomas Huth /* no support for AXI exclusive so always clear C */ 10261074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1027fcf5ef2aSThomas Huth } 1028fcf5ef2aSThomas Huth 1029403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1030fcf5ef2aSThomas Huth } 1031fcf5ef2aSThomas Huth 1032fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc) 1033fcf5ef2aSThomas Huth { 1034403322eaSEdgar E. Iglesias TCGv addr; 1035fcf5ef2aSThomas Huth TCGLabel *swx_skip = NULL; 1036b51b3d43SEdgar E. Iglesias unsigned int size; 1037d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 1038d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 103914776ab5STony Nguyen MemOp mop; 1040fcf5ef2aSThomas Huth 1041fcf5ef2aSThomas Huth mop = dc->opcode & 3; 1042fcf5ef2aSThomas Huth size = 1 << mop; 1043fcf5ef2aSThomas Huth if (!dc->type_b) { 1044d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 1045b51b3d43SEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 1046b51b3d43SEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 1047fcf5ef2aSThomas Huth } 1048fcf5ef2aSThomas Huth mop |= MO_TE; 1049fcf5ef2aSThomas Huth if (rev) { 1050fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 1051fcf5ef2aSThomas Huth } 1052fcf5ef2aSThomas Huth 10539ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 1054fcf5ef2aSThomas Huth return; 1055fcf5ef2aSThomas Huth } 1056fcf5ef2aSThomas Huth 1057d248e1beSEdgar E. Iglesias trap_userspace(dc, ea); 1058d248e1beSEdgar E. Iglesias 1059fcf5ef2aSThomas Huth t_sync_flags(dc); 1060fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 1061fcf5ef2aSThomas Huth sync_jmpstate(dc); 10620dc4af5cSEdgar E. Iglesias /* SWX needs a temp_local. */ 1063403322eaSEdgar E. Iglesias addr = ex ? tcg_temp_local_new() : tcg_temp_new(); 1064d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 1065d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 1066d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 1067fcf5ef2aSThomas Huth 1068fcf5ef2aSThomas Huth if (ex) { /* swx */ 1069cfeea807SEdgar E. Iglesias TCGv_i32 tval; 1070fcf5ef2aSThomas Huth 1071fcf5ef2aSThomas Huth /* swx does not throw unaligned access errors, so force alignment */ 1072403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 1073fcf5ef2aSThomas Huth 10741074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1075fcf5ef2aSThomas Huth swx_skip = gen_new_label(); 10769b158558SRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); 1077fcf5ef2aSThomas Huth 1078071cdc67SEdgar E. Iglesias /* 1079071cdc67SEdgar E. Iglesias * Compare the value loaded at lwx with current contents of 1080071cdc67SEdgar E. Iglesias * the reserved location. 1081071cdc67SEdgar E. Iglesias */ 1082cfeea807SEdgar E. Iglesias tval = tcg_temp_new_i32(); 1083071cdc67SEdgar E. Iglesias 10849b158558SRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val, 1085071cdc67SEdgar E. Iglesias cpu_R[dc->rd], mem_index, 1086071cdc67SEdgar E. Iglesias mop); 1087071cdc67SEdgar E. Iglesias 10889b158558SRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); 10891074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1090cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tval); 1091fcf5ef2aSThomas Huth } 1092fcf5ef2aSThomas Huth 1093fcf5ef2aSThomas Huth if (rev && size != 4) { 1094fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 1095fcf5ef2aSThomas Huth switch (size) { 1096fcf5ef2aSThomas Huth case 1: 1097fcf5ef2aSThomas Huth { 1098a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 1099fcf5ef2aSThomas Huth break; 1100fcf5ef2aSThomas Huth } 1101fcf5ef2aSThomas Huth 1102fcf5ef2aSThomas Huth case 2: 1103fcf5ef2aSThomas Huth /* 00 -> 10 1104fcf5ef2aSThomas Huth 10 -> 00. */ 1105fcf5ef2aSThomas Huth /* Force addr into the temp. */ 1106403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 1107fcf5ef2aSThomas Huth break; 1108fcf5ef2aSThomas Huth default: 1109fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 1110fcf5ef2aSThomas Huth break; 1111fcf5ef2aSThomas Huth } 1112fcf5ef2aSThomas Huth } 1113071cdc67SEdgar E. Iglesias 1114071cdc67SEdgar E. Iglesias if (!ex) { 1115d248e1beSEdgar E. Iglesias tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); 1116071cdc67SEdgar E. Iglesias } 1117fcf5ef2aSThomas Huth 1118fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 11191507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1120a6338015SEdgar E. Iglesias TCGv_i32 t1 = tcg_const_i32(1); 1121a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1122a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1123a6338015SEdgar E. Iglesias 1124d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1125fcf5ef2aSThomas Huth /* FIXME: if the alignment is wrong, we should restore the value 1126fcf5ef2aSThomas Huth * in memory. One possible way to achieve this is to probe 1127fcf5ef2aSThomas Huth * the MMU prior to the memaccess, thay way we could put 1128fcf5ef2aSThomas Huth * the alignment checks in between the probe and the mem 1129fcf5ef2aSThomas Huth * access. 1130fcf5ef2aSThomas Huth */ 1131a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t1, tsize); 1132a6338015SEdgar E. Iglesias 1133a6338015SEdgar E. Iglesias tcg_temp_free_i32(t1); 1134a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1135a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1136fcf5ef2aSThomas Huth } 1137fcf5ef2aSThomas Huth 1138fcf5ef2aSThomas Huth if (ex) { 1139fcf5ef2aSThomas Huth gen_set_label(swx_skip); 1140fcf5ef2aSThomas Huth } 1141fcf5ef2aSThomas Huth 1142403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1143fcf5ef2aSThomas Huth } 1144fcf5ef2aSThomas Huth 1145fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc, 11469e6e1828SEdgar E. Iglesias TCGv_i32 d, TCGv_i32 a) 1147fcf5ef2aSThomas Huth { 1148d89b86e9SEdgar E. Iglesias static const int mb_to_tcg_cc[] = { 1149d89b86e9SEdgar E. Iglesias [CC_EQ] = TCG_COND_EQ, 1150d89b86e9SEdgar E. Iglesias [CC_NE] = TCG_COND_NE, 1151d89b86e9SEdgar E. Iglesias [CC_LT] = TCG_COND_LT, 1152d89b86e9SEdgar E. Iglesias [CC_LE] = TCG_COND_LE, 1153d89b86e9SEdgar E. Iglesias [CC_GE] = TCG_COND_GE, 1154d89b86e9SEdgar E. Iglesias [CC_GT] = TCG_COND_GT, 1155d89b86e9SEdgar E. Iglesias }; 1156d89b86e9SEdgar E. Iglesias 1157fcf5ef2aSThomas Huth switch (cc) { 1158fcf5ef2aSThomas Huth case CC_EQ: 1159fcf5ef2aSThomas Huth case CC_NE: 1160fcf5ef2aSThomas Huth case CC_LT: 1161fcf5ef2aSThomas Huth case CC_LE: 1162fcf5ef2aSThomas Huth case CC_GE: 1163fcf5ef2aSThomas Huth case CC_GT: 11649e6e1828SEdgar E. Iglesias tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); 1165fcf5ef2aSThomas Huth break; 1166fcf5ef2aSThomas Huth default: 1167fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); 1168fcf5ef2aSThomas Huth break; 1169fcf5ef2aSThomas Huth } 1170fcf5ef2aSThomas Huth } 1171fcf5ef2aSThomas Huth 11720f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) 1173fcf5ef2aSThomas Huth { 11740f96e96bSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 1175e956caf2SEdgar E. Iglesias 11760f96e96bSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, 11779b158558SRichard Henderson cpu_btaken, zero, 1178e956caf2SEdgar E. Iglesias pc_true, pc_false); 1179e956caf2SEdgar E. Iglesias 11800f96e96bSRichard Henderson tcg_temp_free_i32(zero); 1181fcf5ef2aSThomas Huth } 1182fcf5ef2aSThomas Huth 1183f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1184f91c60f0SEdgar E. Iglesias { 1185f91c60f0SEdgar E. Iglesias TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)); 1186f91c60f0SEdgar E. Iglesias 1187f91c60f0SEdgar E. Iglesias dc->delayed_branch = 2; 1188f91c60f0SEdgar E. Iglesias dc->tb_flags |= D_FLAG; 1189f91c60f0SEdgar E. Iglesias 1190f91c60f0SEdgar E. Iglesias tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm)); 1191f91c60f0SEdgar E. Iglesias tcg_temp_free_i32(tmp); 1192f91c60f0SEdgar E. Iglesias } 1193f91c60f0SEdgar E. Iglesias 1194fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc) 1195fcf5ef2aSThomas Huth { 1196fcf5ef2aSThomas Huth unsigned int cc; 1197fcf5ef2aSThomas Huth unsigned int dslot; 1198fcf5ef2aSThomas Huth 1199fcf5ef2aSThomas Huth cc = EXTRACT_FIELD(dc->ir, 21, 23); 1200fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 25); 1201fcf5ef2aSThomas Huth 1202fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1203fcf5ef2aSThomas Huth if (dslot) { 1204f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1205fcf5ef2aSThomas Huth } 1206fcf5ef2aSThomas Huth 1207d7ecb757SRichard Henderson if (dc->type_b) { 1208fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT_CC; 1209d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1210d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1211fcf5ef2aSThomas Huth } else { 1212fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 1213d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1214fcf5ef2aSThomas Huth } 12159b158558SRichard Henderson eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); 1216fcf5ef2aSThomas Huth } 1217fcf5ef2aSThomas Huth 1218fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc) 1219fcf5ef2aSThomas Huth { 1220fcf5ef2aSThomas Huth unsigned int dslot, link, abs, mbar; 1221fcf5ef2aSThomas Huth 1222fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 20); 1223fcf5ef2aSThomas Huth abs = dc->ir & (1 << 19); 1224fcf5ef2aSThomas Huth link = dc->ir & (1 << 18); 1225fcf5ef2aSThomas Huth 1226fcf5ef2aSThomas Huth /* Memory barrier. */ 1227fcf5ef2aSThomas Huth mbar = (dc->ir >> 16) & 31; 1228fcf5ef2aSThomas Huth if (mbar == 2 && dc->imm == 4) { 1229badcbf9dSEdgar E. Iglesias uint16_t mbar_imm = dc->rd; 1230badcbf9dSEdgar E. Iglesias 12313f172744SEdgar E. Iglesias /* Data access memory barrier. */ 12323f172744SEdgar E. Iglesias if ((mbar_imm & 2) == 0) { 12333f172744SEdgar E. Iglesias tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 12343f172744SEdgar E. Iglesias } 12353f172744SEdgar E. Iglesias 1236fcf5ef2aSThomas Huth /* mbar IMM & 16 decodes to sleep. */ 1237badcbf9dSEdgar E. Iglesias if (mbar_imm & 16) { 123841ba37c4SRichard Henderson TCGv_i32 tmp_1; 1239fcf5ef2aSThomas Huth 1240b4919e7dSEdgar E. Iglesias if (trap_userspace(dc, true)) { 1241b4919e7dSEdgar E. Iglesias /* Sleep is a privileged instruction. */ 1242b4919e7dSEdgar E. Iglesias return; 1243b4919e7dSEdgar E. Iglesias } 1244b4919e7dSEdgar E. Iglesias 1245fcf5ef2aSThomas Huth t_sync_flags(dc); 124641ba37c4SRichard Henderson 124741ba37c4SRichard Henderson tmp_1 = tcg_const_i32(1); 1248fcf5ef2aSThomas Huth tcg_gen_st_i32(tmp_1, cpu_env, 1249fcf5ef2aSThomas Huth -offsetof(MicroBlazeCPU, env) 1250fcf5ef2aSThomas Huth +offsetof(CPUState, halted)); 1251fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp_1); 125241ba37c4SRichard Henderson 1253d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 125441ba37c4SRichard Henderson 125541ba37c4SRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1256fcf5ef2aSThomas Huth return; 1257fcf5ef2aSThomas Huth } 1258fcf5ef2aSThomas Huth /* Break the TB. */ 1259fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 1260fcf5ef2aSThomas Huth return; 1261fcf5ef2aSThomas Huth } 1262fcf5ef2aSThomas Huth 1263d7ecb757SRichard Henderson if (abs && link && !dslot) { 1264d7ecb757SRichard Henderson if (dc->type_b) { 1265d7ecb757SRichard Henderson /* BRKI */ 1266d7ecb757SRichard Henderson uint32_t imm = dec_alu_typeb_imm(dc); 1267d7ecb757SRichard Henderson if (trap_userspace(dc, imm != 8 && imm != 0x18)) { 1268d7ecb757SRichard Henderson return; 1269d7ecb757SRichard Henderson } 1270d7ecb757SRichard Henderson } else { 1271d7ecb757SRichard Henderson /* BRK */ 1272d7ecb757SRichard Henderson if (trap_userspace(dc, true)) { 1273d7ecb757SRichard Henderson return; 1274d7ecb757SRichard Henderson } 1275d7ecb757SRichard Henderson } 1276d7ecb757SRichard Henderson } 1277d7ecb757SRichard Henderson 1278fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1279fcf5ef2aSThomas Huth if (dslot) { 1280f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1281fcf5ef2aSThomas Huth } 1282d7ecb757SRichard Henderson if (link && dc->rd) { 1283d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1284d7ecb757SRichard Henderson } 1285fcf5ef2aSThomas Huth 1286fcf5ef2aSThomas Huth if (abs) { 1287d7ecb757SRichard Henderson if (dc->type_b) { 1288d7ecb757SRichard Henderson uint32_t dest = dec_alu_typeb_imm(dc); 1289d7ecb757SRichard Henderson 1290d7ecb757SRichard Henderson dc->jmp = JMP_DIRECT; 1291d7ecb757SRichard Henderson dc->jmp_pc = dest; 1292d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dest); 1293fcf5ef2aSThomas Huth if (link && !dslot) { 1294d7ecb757SRichard Henderson switch (dest) { 1295d7ecb757SRichard Henderson case 8: 1296d7ecb757SRichard Henderson case 0x18: 1297d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 1298d7ecb757SRichard Henderson break; 1299d7ecb757SRichard Henderson case 0: 1300d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1301d7ecb757SRichard Henderson break; 1302d7ecb757SRichard Henderson } 1303d7ecb757SRichard Henderson } 1304d7ecb757SRichard Henderson } else { 1305d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1306d7ecb757SRichard Henderson tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]); 1307d7ecb757SRichard Henderson if (link && !dslot) { 130841ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 130941ba37c4SRichard Henderson } 1310fcf5ef2aSThomas Huth } 1311d7ecb757SRichard Henderson } else if (dc->type_b) { 1312fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT; 1313d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1314d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1315fcf5ef2aSThomas Huth } else { 1316d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1317d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1318d7ecb757SRichard Henderson } 13199b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 1320fcf5ef2aSThomas Huth } 1321fcf5ef2aSThomas Huth 1322fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc) 1323fcf5ef2aSThomas Huth { 1324cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1325cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1326cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13273e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13280a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 13290a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1330cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1331fcf5ef2aSThomas Huth 1332cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1333cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1334fcf5ef2aSThomas Huth msr_write(dc, t1); 1335cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1336cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1337fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1338fcf5ef2aSThomas Huth } 1339fcf5ef2aSThomas Huth 1340fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc) 1341fcf5ef2aSThomas Huth { 1342cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1343cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1344cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13453e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13460a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1347cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1348cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1349fcf5ef2aSThomas Huth 1350cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1351cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1352fcf5ef2aSThomas Huth msr_write(dc, t1); 1353cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1354cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1355fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1356fcf5ef2aSThomas Huth } 1357fcf5ef2aSThomas Huth 1358fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc) 1359fcf5ef2aSThomas Huth { 1360cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1361cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1362cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1363fcf5ef2aSThomas Huth 13643e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13650a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1366cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1367cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1368cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1369fcf5ef2aSThomas Huth 1370cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1371cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1372fcf5ef2aSThomas Huth msr_write(dc, t1); 1373cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1374cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1375fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1376fcf5ef2aSThomas Huth } 1377fcf5ef2aSThomas Huth 1378fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc) 1379fcf5ef2aSThomas Huth { 1380fcf5ef2aSThomas Huth unsigned int b_bit, i_bit, e_bit; 1381fcf5ef2aSThomas Huth 1382fcf5ef2aSThomas Huth i_bit = dc->ir & (1 << 21); 1383fcf5ef2aSThomas Huth b_bit = dc->ir & (1 << 22); 1384fcf5ef2aSThomas Huth e_bit = dc->ir & (1 << 23); 1385fcf5ef2aSThomas Huth 1386bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1387bdfc1e88SEdgar E. Iglesias return; 1388bdfc1e88SEdgar E. Iglesias } 1389bdfc1e88SEdgar E. Iglesias 1390f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1391fcf5ef2aSThomas Huth 1392fcf5ef2aSThomas Huth if (i_bit) { 1393fcf5ef2aSThomas Huth dc->tb_flags |= DRTI_FLAG; 1394fcf5ef2aSThomas Huth } else if (b_bit) { 1395fcf5ef2aSThomas Huth dc->tb_flags |= DRTB_FLAG; 1396fcf5ef2aSThomas Huth } else if (e_bit) { 1397fcf5ef2aSThomas Huth dc->tb_flags |= DRTE_FLAG; 139811105d67SRichard Henderson } 1399fcf5ef2aSThomas Huth 1400fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 14019b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 14020f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 1403fcf5ef2aSThomas Huth } 1404fcf5ef2aSThomas Huth 1405fcf5ef2aSThomas Huth static int dec_check_fpuv2(DisasContext *dc) 1406fcf5ef2aSThomas Huth { 1407fcf5ef2aSThomas Huth if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { 140841ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_FPU); 1409fcf5ef2aSThomas Huth } 14102016a6a7SJoe Komlodi return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; 1411fcf5ef2aSThomas Huth } 1412fcf5ef2aSThomas Huth 1413fcf5ef2aSThomas Huth static void dec_fpu(DisasContext *dc) 1414fcf5ef2aSThomas Huth { 1415fcf5ef2aSThomas Huth unsigned int fpu_insn; 1416fcf5ef2aSThomas Huth 14179ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) { 1418fcf5ef2aSThomas Huth return; 1419fcf5ef2aSThomas Huth } 1420fcf5ef2aSThomas Huth 1421fcf5ef2aSThomas Huth fpu_insn = (dc->ir >> 7) & 7; 1422fcf5ef2aSThomas Huth 1423fcf5ef2aSThomas Huth switch (fpu_insn) { 1424fcf5ef2aSThomas Huth case 0: 1425fcf5ef2aSThomas Huth gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1426fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1427fcf5ef2aSThomas Huth break; 1428fcf5ef2aSThomas Huth 1429fcf5ef2aSThomas Huth case 1: 1430fcf5ef2aSThomas Huth gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1431fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1432fcf5ef2aSThomas Huth break; 1433fcf5ef2aSThomas Huth 1434fcf5ef2aSThomas Huth case 2: 1435fcf5ef2aSThomas Huth gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1436fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1437fcf5ef2aSThomas Huth break; 1438fcf5ef2aSThomas Huth 1439fcf5ef2aSThomas Huth case 3: 1440fcf5ef2aSThomas Huth gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1441fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1442fcf5ef2aSThomas Huth break; 1443fcf5ef2aSThomas Huth 1444fcf5ef2aSThomas Huth case 4: 1445fcf5ef2aSThomas Huth switch ((dc->ir >> 4) & 7) { 1446fcf5ef2aSThomas Huth case 0: 1447fcf5ef2aSThomas Huth gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env, 1448fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1449fcf5ef2aSThomas Huth break; 1450fcf5ef2aSThomas Huth case 1: 1451fcf5ef2aSThomas Huth gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env, 1452fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1453fcf5ef2aSThomas Huth break; 1454fcf5ef2aSThomas Huth case 2: 1455fcf5ef2aSThomas Huth gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env, 1456fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1457fcf5ef2aSThomas Huth break; 1458fcf5ef2aSThomas Huth case 3: 1459fcf5ef2aSThomas Huth gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env, 1460fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1461fcf5ef2aSThomas Huth break; 1462fcf5ef2aSThomas Huth case 4: 1463fcf5ef2aSThomas Huth gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env, 1464fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1465fcf5ef2aSThomas Huth break; 1466fcf5ef2aSThomas Huth case 5: 1467fcf5ef2aSThomas Huth gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env, 1468fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1469fcf5ef2aSThomas Huth break; 1470fcf5ef2aSThomas Huth case 6: 1471fcf5ef2aSThomas Huth gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env, 1472fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1473fcf5ef2aSThomas Huth break; 1474fcf5ef2aSThomas Huth default: 1475fcf5ef2aSThomas Huth qemu_log_mask(LOG_UNIMP, 1476fcf5ef2aSThomas Huth "unimplemented fcmp fpu_insn=%x pc=%x" 1477fcf5ef2aSThomas Huth " opc=%x\n", 1478d4705ae0SRichard Henderson fpu_insn, (uint32_t)dc->base.pc_next, 1479d4705ae0SRichard Henderson dc->opcode); 1480fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1481fcf5ef2aSThomas Huth break; 1482fcf5ef2aSThomas Huth } 1483fcf5ef2aSThomas Huth break; 1484fcf5ef2aSThomas Huth 1485fcf5ef2aSThomas Huth case 5: 1486fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1487fcf5ef2aSThomas Huth return; 1488fcf5ef2aSThomas Huth } 1489fcf5ef2aSThomas Huth gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1490fcf5ef2aSThomas Huth break; 1491fcf5ef2aSThomas Huth 1492fcf5ef2aSThomas Huth case 6: 1493fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1494fcf5ef2aSThomas Huth return; 1495fcf5ef2aSThomas Huth } 1496fcf5ef2aSThomas Huth gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1497fcf5ef2aSThomas Huth break; 1498fcf5ef2aSThomas Huth 1499fcf5ef2aSThomas Huth case 7: 1500fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1501fcf5ef2aSThomas Huth return; 1502fcf5ef2aSThomas Huth } 1503fcf5ef2aSThomas Huth gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1504fcf5ef2aSThomas Huth break; 1505fcf5ef2aSThomas Huth 1506fcf5ef2aSThomas Huth default: 1507fcf5ef2aSThomas Huth qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x" 1508fcf5ef2aSThomas Huth " opc=%x\n", 1509d4705ae0SRichard Henderson fpu_insn, (uint32_t)dc->base.pc_next, dc->opcode); 1510fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1511fcf5ef2aSThomas Huth break; 1512fcf5ef2aSThomas Huth } 1513fcf5ef2aSThomas Huth } 1514fcf5ef2aSThomas Huth 1515fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc) 1516fcf5ef2aSThomas Huth { 15179ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 1518fcf5ef2aSThomas Huth return; 1519fcf5ef2aSThomas Huth } 1520d4705ae0SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", 1521d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, dc->opcode); 1522fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1523fcf5ef2aSThomas Huth } 1524fcf5ef2aSThomas Huth 1525fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 1526fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc) 1527fcf5ef2aSThomas Huth { 1528fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1529fcf5ef2aSThomas Huth int ctrl; 1530fcf5ef2aSThomas Huth 1531bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 1532fcf5ef2aSThomas Huth return; 1533fcf5ef2aSThomas Huth } 1534fcf5ef2aSThomas Huth 1535cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 1536fcf5ef2aSThomas Huth if (dc->type_b) { 1537cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 1538fcf5ef2aSThomas Huth ctrl = dc->imm >> 10; 1539fcf5ef2aSThomas Huth } else { 1540cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 1541fcf5ef2aSThomas Huth ctrl = dc->imm >> 5; 1542fcf5ef2aSThomas Huth } 1543fcf5ef2aSThomas Huth 1544cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 1545fcf5ef2aSThomas Huth 1546fcf5ef2aSThomas Huth if (dc->rd == 0) { 1547fcf5ef2aSThomas Huth gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 1548fcf5ef2aSThomas Huth } else { 1549fcf5ef2aSThomas Huth gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 1550fcf5ef2aSThomas Huth } 1551cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1552cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 1553fcf5ef2aSThomas Huth } 1554fcf5ef2aSThomas Huth 1555fcf5ef2aSThomas Huth static struct decoder_info { 1556fcf5ef2aSThomas Huth struct { 1557fcf5ef2aSThomas Huth uint32_t bits; 1558fcf5ef2aSThomas Huth uint32_t mask; 1559fcf5ef2aSThomas Huth }; 1560fcf5ef2aSThomas Huth void (*dec)(DisasContext *dc); 1561fcf5ef2aSThomas Huth } decinfo[] = { 1562fcf5ef2aSThomas Huth {DEC_LD, dec_load}, 1563fcf5ef2aSThomas Huth {DEC_ST, dec_store}, 1564fcf5ef2aSThomas Huth {DEC_IMM, dec_imm}, 1565fcf5ef2aSThomas Huth {DEC_BR, dec_br}, 1566fcf5ef2aSThomas Huth {DEC_BCC, dec_bcc}, 1567fcf5ef2aSThomas Huth {DEC_RTS, dec_rts}, 1568fcf5ef2aSThomas Huth {DEC_FPU, dec_fpu}, 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