14acb54baSEdgar E. Iglesias /* 24acb54baSEdgar E. Iglesias * Xilinx MicroBlaze emulation for qemu: main translation routines. 34acb54baSEdgar E. Iglesias * 44acb54baSEdgar E. Iglesias * Copyright (c) 2009 Edgar E. Iglesias. 5dadc1064SPeter A. G. Crosthwaite * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 64acb54baSEdgar E. Iglesias * 74acb54baSEdgar E. Iglesias * This library is free software; you can redistribute it and/or 84acb54baSEdgar E. Iglesias * modify it under the terms of the GNU Lesser General Public 94acb54baSEdgar E. Iglesias * License as published by the Free Software Foundation; either 104acb54baSEdgar E. Iglesias * version 2 of the License, or (at your option) any later version. 114acb54baSEdgar E. Iglesias * 124acb54baSEdgar E. Iglesias * This library is distributed in the hope that it will be useful, 134acb54baSEdgar E. Iglesias * but WITHOUT ANY WARRANTY; without even the implied warranty of 144acb54baSEdgar E. Iglesias * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 154acb54baSEdgar E. Iglesias * Lesser General Public License for more details. 164acb54baSEdgar E. Iglesias * 174acb54baSEdgar E. Iglesias * You should have received a copy of the GNU Lesser General Public 188167ee88SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 194acb54baSEdgar E. Iglesias */ 204acb54baSEdgar E. Iglesias 218fd9deceSPeter Maydell #include "qemu/osdep.h" 224acb54baSEdgar E. Iglesias #include "cpu.h" 2376cad711SPaolo Bonzini #include "disas/disas.h" 2463c91552SPaolo Bonzini #include "exec/exec-all.h" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 262ef6175aSRichard Henderson #include "exec/helper-proto.h" 274acb54baSEdgar E. Iglesias #include "microblaze-decode.h" 28f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 292ef6175aSRichard Henderson #include "exec/helper-gen.h" 3077fc6f5eSLluís Vilanova #include "exec/translator.h" 3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 324acb54baSEdgar E. Iglesias 33a7e30d84SLluís Vilanova #include "trace-tcg.h" 34508127e2SPaolo Bonzini #include "exec/log.h" 35a7e30d84SLluís Vilanova 364acb54baSEdgar E. Iglesias #define EXTRACT_FIELD(src, start, end) \ 374acb54baSEdgar E. Iglesias (((src) >> start) & ((1 << (end - start + 1)) - 1)) 384acb54baSEdgar E. Iglesias 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; 534acb54baSEdgar E. Iglesias 54022c62cbSPaolo Bonzini #include "exec/gen-icount.h" 554acb54baSEdgar E. Iglesias 564acb54baSEdgar E. Iglesias /* This is the state at translation time. */ 574acb54baSEdgar E. Iglesias typedef struct DisasContext { 58d4705ae0SRichard Henderson DisasContextBase base; 590063ebd6SAndreas Färber MicroBlazeCPU *cpu; 604acb54baSEdgar E. Iglesias 6120800179SRichard Henderson TCGv_i32 r0; 6220800179SRichard Henderson bool r0_set; 6320800179SRichard Henderson 644acb54baSEdgar E. Iglesias /* Decoder. */ 654acb54baSEdgar E. Iglesias int type_b; 664acb54baSEdgar E. Iglesias uint32_t ir; 67d7ecb757SRichard Henderson uint32_t ext_imm; 684acb54baSEdgar E. Iglesias uint8_t opcode; 694acb54baSEdgar E. Iglesias uint8_t rd, ra, rb; 704acb54baSEdgar E. Iglesias uint16_t imm; 714acb54baSEdgar E. Iglesias 724acb54baSEdgar E. Iglesias unsigned int cpustate_changed; 734acb54baSEdgar E. Iglesias unsigned int delayed_branch; 744acb54baSEdgar E. Iglesias unsigned int tb_flags, synced_flags; /* tb dependent flags. */ 754acb54baSEdgar E. Iglesias unsigned int clear_imm; 76287b1defSRichard Henderson int mem_index; 774acb54baSEdgar E. Iglesias 784acb54baSEdgar E. Iglesias #define JMP_NOJMP 0 794acb54baSEdgar E. Iglesias #define JMP_DIRECT 1 80844bab60SEdgar E. Iglesias #define JMP_DIRECT_CC 2 81844bab60SEdgar E. Iglesias #define JMP_INDIRECT 3 824acb54baSEdgar E. Iglesias unsigned int jmp; 834acb54baSEdgar E. Iglesias uint32_t jmp_pc; 844acb54baSEdgar E. Iglesias 854acb54baSEdgar E. Iglesias int abort_at_next_insn; 864acb54baSEdgar E. Iglesias } DisasContext; 874acb54baSEdgar E. Iglesias 8820800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8920800179SRichard Henderson { 9020800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 9120800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 9220800179SRichard Henderson } 9320800179SRichard Henderson return x; 9420800179SRichard Henderson } 9520800179SRichard Henderson 9644d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9744d1432bSRichard Henderson #include "decode-insns.c.inc" 9844d1432bSRichard Henderson 994acb54baSEdgar E. Iglesias static inline void t_sync_flags(DisasContext *dc) 1004acb54baSEdgar E. Iglesias { 1014abf79a4SDong Xu Wang /* Synch the tb dependent flags between translator and runtime. */ 1024acb54baSEdgar E. Iglesias if (dc->tb_flags != dc->synced_flags) { 1039b158558SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags); 1044acb54baSEdgar E. Iglesias dc->synced_flags = dc->tb_flags; 1054acb54baSEdgar E. Iglesias } 1064acb54baSEdgar E. Iglesias } 1074acb54baSEdgar E. Iglesias 108d8e59c4aSRichard Henderson static inline void sync_jmpstate(DisasContext *dc) 109d8e59c4aSRichard Henderson { 110d8e59c4aSRichard Henderson if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 111d8e59c4aSRichard Henderson if (dc->jmp == JMP_DIRECT) { 112d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 113d8e59c4aSRichard Henderson } 114d8e59c4aSRichard Henderson dc->jmp = JMP_INDIRECT; 115d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 116d8e59c4aSRichard Henderson } 117d8e59c4aSRichard Henderson } 118d8e59c4aSRichard Henderson 11941ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 1204acb54baSEdgar E. Iglesias { 1214acb54baSEdgar E. Iglesias TCGv_i32 tmp = tcg_const_i32(index); 1224acb54baSEdgar E. Iglesias 12364254ebaSBlue Swirl gen_helper_raise_exception(cpu_env, tmp); 1244acb54baSEdgar E. Iglesias tcg_temp_free_i32(tmp); 125d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 1264acb54baSEdgar E. Iglesias } 1274acb54baSEdgar E. Iglesias 12841ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 12941ba37c4SRichard Henderson { 13041ba37c4SRichard Henderson t_sync_flags(dc); 131d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 13241ba37c4SRichard Henderson gen_raise_exception(dc, index); 13341ba37c4SRichard Henderson } 13441ba37c4SRichard Henderson 13541ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 13641ba37c4SRichard Henderson { 13741ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 13841ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 13941ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 14041ba37c4SRichard Henderson 14141ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 14241ba37c4SRichard Henderson } 14341ba37c4SRichard Henderson 14490aa39a1SSergey Fedorov static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 14590aa39a1SSergey Fedorov { 14690aa39a1SSergey Fedorov #ifndef CONFIG_USER_ONLY 147d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 14890aa39a1SSergey Fedorov #else 14990aa39a1SSergey Fedorov return true; 15090aa39a1SSergey Fedorov #endif 15190aa39a1SSergey Fedorov } 15290aa39a1SSergey Fedorov 1534acb54baSEdgar E. Iglesias static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 1544acb54baSEdgar E. Iglesias { 155d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1560b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1570b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1580b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1590b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1600b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 1614acb54baSEdgar E. Iglesias tcg_gen_goto_tb(n); 1620f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 163d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 1644acb54baSEdgar E. Iglesias } else { 1650f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 16607ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1674acb54baSEdgar E. Iglesias } 168d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 1694acb54baSEdgar E. Iglesias } 1704acb54baSEdgar E. Iglesias 171bdfc1e88SEdgar E. Iglesias /* 1729ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1739ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1749ba8cd45SEdgar E. Iglesias */ 1759ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1769ba8cd45SEdgar E. Iglesias { 1772c32179fSRichard Henderson if (cond && (dc->tb_flags & MSR_EE) 1785143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 17941ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1809ba8cd45SEdgar E. Iglesias } 1819ba8cd45SEdgar E. Iglesias return cond; 1829ba8cd45SEdgar E. Iglesias } 1839ba8cd45SEdgar E. Iglesias 1849ba8cd45SEdgar E. Iglesias /* 185bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 186bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 187bdfc1e88SEdgar E. Iglesias */ 188bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 189bdfc1e88SEdgar E. Iglesias { 190287b1defSRichard Henderson bool cond_user = cond && dc->mem_index == MMU_USER_IDX; 191bdfc1e88SEdgar E. Iglesias 1922c32179fSRichard Henderson if (cond_user && (dc->tb_flags & MSR_EE)) { 19341ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 194bdfc1e88SEdgar E. Iglesias } 195bdfc1e88SEdgar E. Iglesias return cond_user; 196bdfc1e88SEdgar E. Iglesias } 197bdfc1e88SEdgar E. Iglesias 198d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc) 19961204ce8SEdgar E. Iglesias { 200d7ecb757SRichard Henderson tcg_debug_assert(dc->type_b); 20120800179SRichard Henderson return typeb_imm(dc, (int16_t)dc->imm); 20261204ce8SEdgar E. Iglesias } 20361204ce8SEdgar E. Iglesias 204cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) 2054acb54baSEdgar E. Iglesias { 2064acb54baSEdgar E. Iglesias if (dc->type_b) { 207d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc)); 2089b158558SRichard Henderson return &cpu_imm; 209d7ecb757SRichard Henderson } 2104acb54baSEdgar E. Iglesias return &cpu_R[dc->rb]; 2114acb54baSEdgar E. Iglesias } 2124acb54baSEdgar E. Iglesias 21320800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 2144acb54baSEdgar E. Iglesias { 21520800179SRichard Henderson if (likely(reg != 0)) { 21620800179SRichard Henderson return cpu_R[reg]; 2174acb54baSEdgar E. Iglesias } 21820800179SRichard Henderson if (!dc->r0_set) { 21920800179SRichard Henderson if (dc->r0 == NULL) { 22020800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 2214acb54baSEdgar E. Iglesias } 22220800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 22320800179SRichard Henderson dc->r0_set = true; 22420800179SRichard Henderson } 22520800179SRichard Henderson return dc->r0; 22640cbf5b7SEdgar E. Iglesias } 22740cbf5b7SEdgar E. Iglesias 22820800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 22920800179SRichard Henderson { 23020800179SRichard Henderson if (likely(reg != 0)) { 23120800179SRichard Henderson return cpu_R[reg]; 23220800179SRichard Henderson } 23320800179SRichard Henderson if (dc->r0 == NULL) { 23420800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 23520800179SRichard Henderson } 23620800179SRichard Henderson return dc->r0; 23740cbf5b7SEdgar E. Iglesias } 23840cbf5b7SEdgar E. Iglesias 23920800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 24020800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 24120800179SRichard Henderson { 24220800179SRichard Henderson TCGv_i32 rd, ra, rb; 24320800179SRichard Henderson 24420800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 24520800179SRichard Henderson return true; 24640cbf5b7SEdgar E. Iglesias } 24720800179SRichard Henderson 24820800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 24920800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 25020800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 25120800179SRichard Henderson fn(rd, ra, rb); 25220800179SRichard Henderson return true; 25320800179SRichard Henderson } 25420800179SRichard Henderson 25539cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects, 25639cf3864SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32)) 25739cf3864SRichard Henderson { 25839cf3864SRichard Henderson TCGv_i32 rd, ra; 25939cf3864SRichard Henderson 26039cf3864SRichard Henderson if (arg->rd == 0 && !side_effects) { 26139cf3864SRichard Henderson return true; 26239cf3864SRichard Henderson } 26339cf3864SRichard Henderson 26439cf3864SRichard Henderson rd = reg_for_write(dc, arg->rd); 26539cf3864SRichard Henderson ra = reg_for_read(dc, arg->ra); 26639cf3864SRichard Henderson fn(rd, ra); 26739cf3864SRichard Henderson return true; 26839cf3864SRichard Henderson } 26939cf3864SRichard Henderson 27020800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 27120800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 27220800179SRichard Henderson { 27320800179SRichard Henderson TCGv_i32 rd, ra; 27420800179SRichard Henderson 27520800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 27620800179SRichard Henderson return true; 27720800179SRichard Henderson } 27820800179SRichard Henderson 27920800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 28020800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 28120800179SRichard Henderson fni(rd, ra, arg->imm); 28220800179SRichard Henderson return true; 28320800179SRichard Henderson } 28420800179SRichard Henderson 28520800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 28620800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 28720800179SRichard Henderson { 28820800179SRichard Henderson TCGv_i32 rd, ra, imm; 28920800179SRichard Henderson 29020800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 29120800179SRichard Henderson return true; 29220800179SRichard Henderson } 29320800179SRichard Henderson 29420800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 29520800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 29620800179SRichard Henderson imm = tcg_const_i32(arg->imm); 29720800179SRichard Henderson 29820800179SRichard Henderson fn(rd, ra, imm); 29920800179SRichard Henderson 30020800179SRichard Henderson tcg_temp_free_i32(imm); 30120800179SRichard Henderson return true; 30220800179SRichard Henderson } 30320800179SRichard Henderson 30420800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 30520800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 30620800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 30720800179SRichard Henderson 308607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \ 309607f5767SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 310607f5767SRichard Henderson { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); } 311607f5767SRichard Henderson 31239cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \ 31339cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 31439cf3864SRichard Henderson { return do_typea0(dc, a, SE, FN); } 31539cf3864SRichard Henderson 31639cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \ 31739cf3864SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \ 31839cf3864SRichard Henderson { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); } 31939cf3864SRichard Henderson 32020800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 32120800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 32220800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 32320800179SRichard Henderson 32497955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \ 32597955cebSRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 32697955cebSRichard Henderson { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); } 32797955cebSRichard Henderson 32820800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 32920800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 33020800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 33120800179SRichard Henderson 332d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \ 333d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina) \ 334d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina); } 335d5aead3dSRichard Henderson 336d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \ 337d5aead3dSRichard Henderson static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \ 338d5aead3dSRichard Henderson { HELPER(out, cpu_env, ina, inb); } 339d5aead3dSRichard Henderson 34020800179SRichard Henderson /* No input carry, but output carry. */ 34120800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 34220800179SRichard Henderson { 34320800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 34420800179SRichard Henderson 34520800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 34620800179SRichard Henderson 34720800179SRichard Henderson tcg_temp_free_i32(zero); 34820800179SRichard Henderson } 34920800179SRichard Henderson 35020800179SRichard Henderson /* Input and output carry. */ 35120800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 35220800179SRichard Henderson { 35320800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 35420800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 35520800179SRichard Henderson 35620800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 35720800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 35820800179SRichard Henderson 35920800179SRichard Henderson tcg_temp_free_i32(tmp); 36020800179SRichard Henderson tcg_temp_free_i32(zero); 36120800179SRichard Henderson } 36220800179SRichard Henderson 36320800179SRichard Henderson /* Input carry, but no output carry. */ 36420800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 36520800179SRichard Henderson { 36620800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 36720800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 36820800179SRichard Henderson } 36920800179SRichard Henderson 37020800179SRichard Henderson DO_TYPEA(add, true, gen_add) 37120800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 37220800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 37320800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 37420800179SRichard Henderson 37520800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 37620800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 37720800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 37820800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 37920800179SRichard Henderson 380cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 381cb0a0a4cSRichard Henderson { 382cb0a0a4cSRichard Henderson tcg_gen_andi_i32(out, ina, ~imm); 383cb0a0a4cSRichard Henderson } 384cb0a0a4cSRichard Henderson 385cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32) 386cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32) 387cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32) 388cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni) 389cb0a0a4cSRichard Henderson 390081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 391081d8e02SRichard Henderson { 392081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 393081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 394081d8e02SRichard Henderson tcg_gen_sar_i32(out, ina, tmp); 395081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 396081d8e02SRichard Henderson } 397081d8e02SRichard Henderson 398081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 399081d8e02SRichard Henderson { 400081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 401081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 402081d8e02SRichard Henderson tcg_gen_shr_i32(out, ina, tmp); 403081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 404081d8e02SRichard Henderson } 405081d8e02SRichard Henderson 406081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 407081d8e02SRichard Henderson { 408081d8e02SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 409081d8e02SRichard Henderson tcg_gen_andi_i32(tmp, inb, 31); 410081d8e02SRichard Henderson tcg_gen_shl_i32(out, ina, tmp); 411081d8e02SRichard Henderson tcg_temp_free_i32(tmp); 412081d8e02SRichard Henderson } 413081d8e02SRichard Henderson 414081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 415081d8e02SRichard Henderson { 416081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 417081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 418081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 419081d8e02SRichard Henderson 420081d8e02SRichard Henderson if (imm_w + imm_s > 32 || imm_w == 0) { 421081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 422081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 423081d8e02SRichard Henderson imm_w, imm_s); 424081d8e02SRichard Henderson } else { 425081d8e02SRichard Henderson tcg_gen_extract_i32(out, ina, imm_s, imm_w); 426081d8e02SRichard Henderson } 427081d8e02SRichard Henderson } 428081d8e02SRichard Henderson 429081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm) 430081d8e02SRichard Henderson { 431081d8e02SRichard Henderson /* Note that decodetree has extracted and reassembled imm_w/imm_s. */ 432081d8e02SRichard Henderson int imm_w = extract32(imm, 5, 5); 433081d8e02SRichard Henderson int imm_s = extract32(imm, 0, 5); 434081d8e02SRichard Henderson int width = imm_w - imm_s + 1; 435081d8e02SRichard Henderson 436081d8e02SRichard Henderson if (imm_w < imm_s) { 437081d8e02SRichard Henderson /* These inputs have an undefined behavior. */ 438081d8e02SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 439081d8e02SRichard Henderson imm_w, imm_s); 440081d8e02SRichard Henderson } else { 441081d8e02SRichard Henderson tcg_gen_deposit_i32(out, out, ina, imm_s, width); 442081d8e02SRichard Henderson } 443081d8e02SRichard Henderson } 444081d8e02SRichard Henderson 445081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra) 446081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl) 447081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll) 448081d8e02SRichard Henderson 449081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32) 450081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32) 451081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32) 452081d8e02SRichard Henderson 453081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi) 454081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi) 455081d8e02SRichard Henderson 45639cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina) 45739cf3864SRichard Henderson { 45839cf3864SRichard Henderson tcg_gen_clzi_i32(out, ina, 32); 45939cf3864SRichard Henderson } 46039cf3864SRichard Henderson 46139cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz) 46239cf3864SRichard Henderson 46358b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 46458b48b63SRichard Henderson { 46558b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 46658b48b63SRichard Henderson 46758b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina); 46858b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 46958b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 47058b48b63SRichard Henderson tcg_temp_free_i32(lt); 47158b48b63SRichard Henderson } 47258b48b63SRichard Henderson 47358b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 47458b48b63SRichard Henderson { 47558b48b63SRichard Henderson TCGv_i32 lt = tcg_temp_new_i32(); 47658b48b63SRichard Henderson 47758b48b63SRichard Henderson tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina); 47858b48b63SRichard Henderson tcg_gen_sub_i32(out, inb, ina); 47958b48b63SRichard Henderson tcg_gen_deposit_i32(out, out, lt, 31, 1); 48058b48b63SRichard Henderson tcg_temp_free_i32(lt); 48158b48b63SRichard Henderson } 48258b48b63SRichard Henderson 48358b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp) 48458b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu) 485a2b0b90eSRichard Henderson 486d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd) 487d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub) 488d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul) 489d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv) 490d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un) 491d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt) 492d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq) 493d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le) 494d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt) 495d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne) 496d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge) 497d5aead3dSRichard Henderson 498d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd) 499d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub) 500d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul) 501d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv) 502d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un) 503d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt) 504d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq) 505d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le) 506d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt) 507d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne) 508d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge) 509d5aead3dSRichard Henderson 510d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt) 511d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint) 512d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt) 513d5aead3dSRichard Henderson 514d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt) 515d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint) 516d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt) 517d5aead3dSRichard Henderson 518d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */ 519b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 520b1354342SRichard Henderson { 521b1354342SRichard Henderson gen_helper_divs(out, cpu_env, inb, ina); 522b1354342SRichard Henderson } 523b1354342SRichard Henderson 524b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 525b1354342SRichard Henderson { 526b1354342SRichard Henderson gen_helper_divu(out, cpu_env, inb, ina); 527b1354342SRichard Henderson } 528b1354342SRichard Henderson 529b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv) 530b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu) 531b1354342SRichard Henderson 532e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg) 533e64b2e5cSRichard Henderson { 534e64b2e5cSRichard Henderson dc->ext_imm = arg->imm << 16; 535e64b2e5cSRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 536e64b2e5cSRichard Henderson dc->tb_flags |= IMM_FLAG; 537e64b2e5cSRichard Henderson dc->clear_imm = 0; 538e64b2e5cSRichard Henderson return true; 539e64b2e5cSRichard Henderson } 540e64b2e5cSRichard Henderson 54197955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 54297955cebSRichard Henderson { 54397955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 54497955cebSRichard Henderson tcg_gen_muls2_i32(tmp, out, ina, inb); 54597955cebSRichard Henderson tcg_temp_free_i32(tmp); 54697955cebSRichard Henderson } 54797955cebSRichard Henderson 54897955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 54997955cebSRichard Henderson { 55097955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 55197955cebSRichard Henderson tcg_gen_mulu2_i32(tmp, out, ina, inb); 55297955cebSRichard Henderson tcg_temp_free_i32(tmp); 55397955cebSRichard Henderson } 55497955cebSRichard Henderson 55597955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 55697955cebSRichard Henderson { 55797955cebSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 55897955cebSRichard Henderson tcg_gen_mulsu2_i32(tmp, out, ina, inb); 55997955cebSRichard Henderson tcg_temp_free_i32(tmp); 56097955cebSRichard Henderson } 56197955cebSRichard Henderson 56297955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32) 56397955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh) 56497955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu) 56597955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu) 56697955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32) 56797955cebSRichard Henderson 568cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32) 569cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32) 570cb0a0a4cSRichard Henderson 571607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 572607f5767SRichard Henderson { 573607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb); 574607f5767SRichard Henderson } 575607f5767SRichard Henderson 576607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 577607f5767SRichard Henderson { 578607f5767SRichard Henderson tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb); 579607f5767SRichard Henderson } 580607f5767SRichard Henderson 581607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf) 582607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq) 583607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne) 584607f5767SRichard Henderson 585a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 586a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 587a2b0b90eSRichard Henderson { 588a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 589a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 590a2b0b90eSRichard Henderson } 591a2b0b90eSRichard Henderson 592a2b0b90eSRichard Henderson /* Input and output carry. */ 593a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 594a2b0b90eSRichard Henderson { 595a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 596a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 597a2b0b90eSRichard Henderson 598a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 599a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 600a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 601a2b0b90eSRichard Henderson 602a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 603a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 604a2b0b90eSRichard Henderson } 605a2b0b90eSRichard Henderson 606a2b0b90eSRichard Henderson /* No input or output carry. */ 607a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 608a2b0b90eSRichard Henderson { 609a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 610a2b0b90eSRichard Henderson } 611a2b0b90eSRichard Henderson 612a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 613a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 614a2b0b90eSRichard Henderson { 615a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 616a2b0b90eSRichard Henderson 617a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 618a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 619a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 620a2b0b90eSRichard Henderson 621a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 622a2b0b90eSRichard Henderson } 623a2b0b90eSRichard Henderson 624a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 625a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 626a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 627a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 628a2b0b90eSRichard Henderson 629a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 630a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 631a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 632a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 633a2b0b90eSRichard Henderson 63439cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32) 63539cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32) 63639cf3864SRichard Henderson 63739cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina) 63839cf3864SRichard Henderson { 63939cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 64039cf3864SRichard Henderson tcg_gen_sari_i32(out, ina, 1); 64139cf3864SRichard Henderson } 64239cf3864SRichard Henderson 64339cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina) 64439cf3864SRichard Henderson { 64539cf3864SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 64639cf3864SRichard Henderson 64739cf3864SRichard Henderson tcg_gen_mov_i32(tmp, cpu_msr_c); 64839cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 64939cf3864SRichard Henderson tcg_gen_extract2_i32(out, ina, tmp, 1); 65039cf3864SRichard Henderson 65139cf3864SRichard Henderson tcg_temp_free_i32(tmp); 65239cf3864SRichard Henderson } 65339cf3864SRichard Henderson 65439cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina) 65539cf3864SRichard Henderson { 65639cf3864SRichard Henderson tcg_gen_andi_i32(cpu_msr_c, ina, 1); 65739cf3864SRichard Henderson tcg_gen_shri_i32(out, ina, 1); 65839cf3864SRichard Henderson } 65939cf3864SRichard Henderson 66039cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra) 66139cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src) 66239cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl) 66339cf3864SRichard Henderson 66439cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina) 66539cf3864SRichard Henderson { 66639cf3864SRichard Henderson tcg_gen_rotri_i32(out, ina, 16); 66739cf3864SRichard Henderson } 66839cf3864SRichard Henderson 66939cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32) 67039cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph) 67139cf3864SRichard Henderson 67239cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a) 67339cf3864SRichard Henderson { 67439cf3864SRichard Henderson /* Cache operations are nops: only check for supervisor mode. */ 67539cf3864SRichard Henderson trap_userspace(dc, true); 67639cf3864SRichard Henderson return true; 67739cf3864SRichard Henderson } 67839cf3864SRichard Henderson 679cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32) 680cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32) 681cb0a0a4cSRichard Henderson 682d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) 683d8e59c4aSRichard Henderson { 684d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 685d8e59c4aSRichard Henderson 686d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 687d8e59c4aSRichard Henderson if (ra && rb) { 688d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 689d8e59c4aSRichard Henderson tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); 690d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 691d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 692d8e59c4aSRichard Henderson } else if (ra) { 693d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 694d8e59c4aSRichard Henderson } else if (rb) { 695d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 696d8e59c4aSRichard Henderson } else { 697d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 698d8e59c4aSRichard Henderson } 699d8e59c4aSRichard Henderson 700d8e59c4aSRichard Henderson if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) { 701d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 702d8e59c4aSRichard Henderson } 703d8e59c4aSRichard Henderson return ret; 704d8e59c4aSRichard Henderson } 705d8e59c4aSRichard Henderson 706d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) 707d8e59c4aSRichard Henderson { 708d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 709d8e59c4aSRichard Henderson 710d8e59c4aSRichard Henderson /* If any of the regs is r0, set t to the value of the other reg. */ 711d8e59c4aSRichard Henderson if (ra) { 712d8e59c4aSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 713d8e59c4aSRichard Henderson tcg_gen_addi_i32(tmp, cpu_R[ra], imm); 714d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, tmp); 715d8e59c4aSRichard Henderson tcg_temp_free_i32(tmp); 716d8e59c4aSRichard Henderson } else { 717d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, (uint32_t)imm); 718d8e59c4aSRichard Henderson } 719d8e59c4aSRichard Henderson 720d8e59c4aSRichard Henderson if (ra == 1 && dc->cpu->cfg.stackprot) { 721d8e59c4aSRichard Henderson gen_helper_stackprot(cpu_env, ret); 722d8e59c4aSRichard Henderson } 723d8e59c4aSRichard Henderson return ret; 724d8e59c4aSRichard Henderson } 725d8e59c4aSRichard Henderson 726d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) 727d8e59c4aSRichard Henderson { 728d8e59c4aSRichard Henderson int addr_size = dc->cpu->cfg.addr_size; 729d8e59c4aSRichard Henderson TCGv ret = tcg_temp_new(); 730d8e59c4aSRichard Henderson 731d8e59c4aSRichard Henderson if (addr_size == 32 || ra == 0) { 732d8e59c4aSRichard Henderson if (rb) { 733d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[rb]); 734d8e59c4aSRichard Henderson } else { 735d8e59c4aSRichard Henderson tcg_gen_movi_tl(ret, 0); 736d8e59c4aSRichard Henderson } 737d8e59c4aSRichard Henderson } else { 738d8e59c4aSRichard Henderson if (rb) { 739d8e59c4aSRichard Henderson tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); 740d8e59c4aSRichard Henderson } else { 741d8e59c4aSRichard Henderson tcg_gen_extu_i32_tl(ret, cpu_R[ra]); 742d8e59c4aSRichard Henderson tcg_gen_shli_tl(ret, ret, 32); 743d8e59c4aSRichard Henderson } 744d8e59c4aSRichard Henderson if (addr_size < 64) { 745d8e59c4aSRichard Henderson /* Mask off out of range bits. */ 746d8e59c4aSRichard Henderson tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size)); 747d8e59c4aSRichard Henderson } 748d8e59c4aSRichard Henderson } 749d8e59c4aSRichard Henderson return ret; 750d8e59c4aSRichard Henderson } 751d8e59c4aSRichard Henderson 752d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop, 753d8e59c4aSRichard Henderson int mem_index, bool rev) 754d8e59c4aSRichard Henderson { 755d8e59c4aSRichard Henderson TCGv_i32 v; 756d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 757d8e59c4aSRichard Henderson 758d8e59c4aSRichard Henderson /* 759d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 760d8e59c4aSRichard Henderson * 761d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 762d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 763d8e59c4aSRichard Henderson */ 764d8e59c4aSRichard Henderson if (rev) { 765d8e59c4aSRichard Henderson if (size > MO_8) { 766d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 767d8e59c4aSRichard Henderson } 768d8e59c4aSRichard Henderson if (size < MO_32) { 769d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 770d8e59c4aSRichard Henderson } 771d8e59c4aSRichard Henderson } 772d8e59c4aSRichard Henderson 773d8e59c4aSRichard Henderson t_sync_flags(dc); 774d8e59c4aSRichard Henderson sync_jmpstate(dc); 775d8e59c4aSRichard Henderson 776d8e59c4aSRichard Henderson /* 777d8e59c4aSRichard Henderson * Microblaze gives MMU faults priority over faults due to 778d8e59c4aSRichard Henderson * unaligned addresses. That's why we speculatively do the load 779d8e59c4aSRichard Henderson * into v. If the load succeeds, we verify alignment of the 780d8e59c4aSRichard Henderson * address and if that succeeds we write into the destination reg. 781d8e59c4aSRichard Henderson */ 782d8e59c4aSRichard Henderson v = tcg_temp_new_i32(); 783d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); 784d8e59c4aSRichard Henderson 785d8e59c4aSRichard Henderson /* TODO: Convert to CPUClass::do_unaligned_access. */ 786d8e59c4aSRichard Henderson if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) { 787d8e59c4aSRichard Henderson TCGv_i32 t0 = tcg_const_i32(0); 788d8e59c4aSRichard Henderson TCGv_i32 treg = tcg_const_i32(rd); 789d8e59c4aSRichard Henderson TCGv_i32 tsize = tcg_const_i32((1 << size) - 1); 790d8e59c4aSRichard Henderson 791d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 792d8e59c4aSRichard Henderson gen_helper_memalign(cpu_env, addr, treg, t0, tsize); 793d8e59c4aSRichard Henderson 794d8e59c4aSRichard Henderson tcg_temp_free_i32(t0); 795d8e59c4aSRichard Henderson tcg_temp_free_i32(treg); 796d8e59c4aSRichard Henderson tcg_temp_free_i32(tsize); 797d8e59c4aSRichard Henderson } 798d8e59c4aSRichard Henderson 799d8e59c4aSRichard Henderson if (rd) { 800d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[rd], v); 801d8e59c4aSRichard Henderson } 802d8e59c4aSRichard Henderson 803d8e59c4aSRichard Henderson tcg_temp_free_i32(v); 804d8e59c4aSRichard Henderson tcg_temp_free(addr); 805d8e59c4aSRichard Henderson return true; 806d8e59c4aSRichard Henderson } 807d8e59c4aSRichard Henderson 808d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg) 809d8e59c4aSRichard Henderson { 810d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 811d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 812d8e59c4aSRichard Henderson } 813d8e59c4aSRichard Henderson 814d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg) 815d8e59c4aSRichard Henderson { 816d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 817d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 818d8e59c4aSRichard Henderson } 819d8e59c4aSRichard Henderson 820d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg) 821d8e59c4aSRichard Henderson { 822d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 823d8e59c4aSRichard Henderson return true; 824d8e59c4aSRichard Henderson } 825d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 826d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 827d8e59c4aSRichard Henderson } 828d8e59c4aSRichard Henderson 829d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg) 830d8e59c4aSRichard Henderson { 831d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 832d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 833d8e59c4aSRichard Henderson } 834d8e59c4aSRichard Henderson 835d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg) 836d8e59c4aSRichard Henderson { 837d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 838d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 839d8e59c4aSRichard Henderson } 840d8e59c4aSRichard Henderson 841d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg) 842d8e59c4aSRichard Henderson { 843d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 844d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 845d8e59c4aSRichard Henderson } 846d8e59c4aSRichard Henderson 847d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg) 848d8e59c4aSRichard Henderson { 849d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 850d8e59c4aSRichard Henderson return true; 851d8e59c4aSRichard Henderson } 852d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 853d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 854d8e59c4aSRichard Henderson } 855d8e59c4aSRichard Henderson 856d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg) 857d8e59c4aSRichard Henderson { 858d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 859d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 860d8e59c4aSRichard Henderson } 861d8e59c4aSRichard Henderson 862d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg) 863d8e59c4aSRichard Henderson { 864d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 865d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 866d8e59c4aSRichard Henderson } 867d8e59c4aSRichard Henderson 868d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg) 869d8e59c4aSRichard Henderson { 870d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 871d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 872d8e59c4aSRichard Henderson } 873d8e59c4aSRichard Henderson 874d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg) 875d8e59c4aSRichard Henderson { 876d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 877d8e59c4aSRichard Henderson return true; 878d8e59c4aSRichard Henderson } 879d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 880d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 881d8e59c4aSRichard Henderson } 882d8e59c4aSRichard Henderson 883d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg) 884d8e59c4aSRichard Henderson { 885d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 886d8e59c4aSRichard Henderson return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 887d8e59c4aSRichard Henderson } 888d8e59c4aSRichard Henderson 889d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg) 890d8e59c4aSRichard Henderson { 891d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 892d8e59c4aSRichard Henderson 893d8e59c4aSRichard Henderson /* lwx does not throw unaligned access errors, so force alignment */ 894d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 895d8e59c4aSRichard Henderson 896d8e59c4aSRichard Henderson t_sync_flags(dc); 897d8e59c4aSRichard Henderson sync_jmpstate(dc); 898d8e59c4aSRichard Henderson 899d8e59c4aSRichard Henderson tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL); 900d8e59c4aSRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 901d8e59c4aSRichard Henderson tcg_temp_free(addr); 902d8e59c4aSRichard Henderson 903d8e59c4aSRichard Henderson if (arg->rd) { 904d8e59c4aSRichard Henderson tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val); 905d8e59c4aSRichard Henderson } 906d8e59c4aSRichard Henderson 907d8e59c4aSRichard Henderson /* No support for AXI exclusive so always clear C */ 908d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 909d8e59c4aSRichard Henderson return true; 910d8e59c4aSRichard Henderson } 911d8e59c4aSRichard Henderson 912d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop, 913d8e59c4aSRichard Henderson int mem_index, bool rev) 914d8e59c4aSRichard Henderson { 915d8e59c4aSRichard Henderson MemOp size = mop & MO_SIZE; 916d8e59c4aSRichard Henderson 917d8e59c4aSRichard Henderson /* 918d8e59c4aSRichard Henderson * When doing reverse accesses we need to do two things. 919d8e59c4aSRichard Henderson * 920d8e59c4aSRichard Henderson * 1. Reverse the address wrt endianness. 921d8e59c4aSRichard Henderson * 2. Byteswap the data lanes on the way back into the CPU core. 922d8e59c4aSRichard Henderson */ 923d8e59c4aSRichard Henderson if (rev) { 924d8e59c4aSRichard Henderson if (size > MO_8) { 925d8e59c4aSRichard Henderson mop ^= MO_BSWAP; 926d8e59c4aSRichard Henderson } 927d8e59c4aSRichard Henderson if (size < MO_32) { 928d8e59c4aSRichard Henderson tcg_gen_xori_tl(addr, addr, 3 - size); 929d8e59c4aSRichard Henderson } 930d8e59c4aSRichard Henderson } 931d8e59c4aSRichard Henderson 932d8e59c4aSRichard Henderson t_sync_flags(dc); 933d8e59c4aSRichard Henderson sync_jmpstate(dc); 934d8e59c4aSRichard Henderson 935d8e59c4aSRichard Henderson tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop); 936d8e59c4aSRichard Henderson 937d8e59c4aSRichard Henderson /* TODO: Convert to CPUClass::do_unaligned_access. */ 938d8e59c4aSRichard Henderson if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) { 939d8e59c4aSRichard Henderson TCGv_i32 t1 = tcg_const_i32(1); 940d8e59c4aSRichard Henderson TCGv_i32 treg = tcg_const_i32(rd); 941d8e59c4aSRichard Henderson TCGv_i32 tsize = tcg_const_i32((1 << size) - 1); 942d8e59c4aSRichard Henderson 943d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 944d8e59c4aSRichard Henderson /* FIXME: if the alignment is wrong, we should restore the value 945d8e59c4aSRichard Henderson * in memory. One possible way to achieve this is to probe 946d8e59c4aSRichard Henderson * the MMU prior to the memaccess, thay way we could put 947d8e59c4aSRichard Henderson * the alignment checks in between the probe and the mem 948d8e59c4aSRichard Henderson * access. 949d8e59c4aSRichard Henderson */ 950d8e59c4aSRichard Henderson gen_helper_memalign(cpu_env, addr, treg, t1, tsize); 951d8e59c4aSRichard Henderson 952d8e59c4aSRichard Henderson tcg_temp_free_i32(t1); 953d8e59c4aSRichard Henderson tcg_temp_free_i32(treg); 954d8e59c4aSRichard Henderson tcg_temp_free_i32(tsize); 955d8e59c4aSRichard Henderson } 956d8e59c4aSRichard Henderson 957d8e59c4aSRichard Henderson tcg_temp_free(addr); 958d8e59c4aSRichard Henderson return true; 959d8e59c4aSRichard Henderson } 960d8e59c4aSRichard Henderson 961d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg) 962d8e59c4aSRichard Henderson { 963d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 964d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 965d8e59c4aSRichard Henderson } 966d8e59c4aSRichard Henderson 967d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg) 968d8e59c4aSRichard Henderson { 969d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 970d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true); 971d8e59c4aSRichard Henderson } 972d8e59c4aSRichard Henderson 973d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg) 974d8e59c4aSRichard Henderson { 975d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 976d8e59c4aSRichard Henderson return true; 977d8e59c4aSRichard Henderson } 978d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 979d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); 980d8e59c4aSRichard Henderson } 981d8e59c4aSRichard Henderson 982d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg) 983d8e59c4aSRichard Henderson { 984d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 985d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false); 986d8e59c4aSRichard Henderson } 987d8e59c4aSRichard Henderson 988d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg) 989d8e59c4aSRichard Henderson { 990d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 991d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 992d8e59c4aSRichard Henderson } 993d8e59c4aSRichard Henderson 994d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg) 995d8e59c4aSRichard Henderson { 996d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 997d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true); 998d8e59c4aSRichard Henderson } 999d8e59c4aSRichard Henderson 1000d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg) 1001d8e59c4aSRichard Henderson { 1002d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 1003d8e59c4aSRichard Henderson return true; 1004d8e59c4aSRichard Henderson } 1005d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 1006d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false); 1007d8e59c4aSRichard Henderson } 1008d8e59c4aSRichard Henderson 1009d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg) 1010d8e59c4aSRichard Henderson { 1011d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 1012d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false); 1013d8e59c4aSRichard Henderson } 1014d8e59c4aSRichard Henderson 1015d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg) 1016d8e59c4aSRichard Henderson { 1017d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1018d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 1019d8e59c4aSRichard Henderson } 1020d8e59c4aSRichard Henderson 1021d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg) 1022d8e59c4aSRichard Henderson { 1023d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1024d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true); 1025d8e59c4aSRichard Henderson } 1026d8e59c4aSRichard Henderson 1027d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg) 1028d8e59c4aSRichard Henderson { 1029d8e59c4aSRichard Henderson if (trap_userspace(dc, true)) { 1030d8e59c4aSRichard Henderson return true; 1031d8e59c4aSRichard Henderson } 1032d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); 1033d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false); 1034d8e59c4aSRichard Henderson } 1035d8e59c4aSRichard Henderson 1036d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg) 1037d8e59c4aSRichard Henderson { 1038d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm); 1039d8e59c4aSRichard Henderson return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false); 1040d8e59c4aSRichard Henderson } 1041d8e59c4aSRichard Henderson 1042d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg) 1043d8e59c4aSRichard Henderson { 1044d8e59c4aSRichard Henderson TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb); 1045d8e59c4aSRichard Henderson TCGLabel *swx_done = gen_new_label(); 1046d8e59c4aSRichard Henderson TCGLabel *swx_fail = gen_new_label(); 1047d8e59c4aSRichard Henderson TCGv_i32 tval; 1048d8e59c4aSRichard Henderson 1049d8e59c4aSRichard Henderson t_sync_flags(dc); 1050d8e59c4aSRichard Henderson sync_jmpstate(dc); 1051d8e59c4aSRichard Henderson 1052d8e59c4aSRichard Henderson /* swx does not throw unaligned access errors, so force alignment */ 1053d8e59c4aSRichard Henderson tcg_gen_andi_tl(addr, addr, ~3); 1054d8e59c4aSRichard Henderson 1055d8e59c4aSRichard Henderson /* 1056d8e59c4aSRichard Henderson * Compare the address vs the one we used during lwx. 1057d8e59c4aSRichard Henderson * On mismatch, the operation fails. On match, addr dies at the 1058d8e59c4aSRichard Henderson * branch, but we know we can use the equal version in the global. 1059d8e59c4aSRichard Henderson * In either case, addr is no longer needed. 1060d8e59c4aSRichard Henderson */ 1061d8e59c4aSRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail); 1062d8e59c4aSRichard Henderson tcg_temp_free(addr); 1063d8e59c4aSRichard Henderson 1064d8e59c4aSRichard Henderson /* 1065d8e59c4aSRichard Henderson * Compare the value loaded during lwx with current contents of 1066d8e59c4aSRichard Henderson * the reserved location. 1067d8e59c4aSRichard Henderson */ 1068d8e59c4aSRichard Henderson tval = tcg_temp_new_i32(); 1069d8e59c4aSRichard Henderson 1070d8e59c4aSRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val, 1071d8e59c4aSRichard Henderson reg_for_write(dc, arg->rd), 1072d8e59c4aSRichard Henderson dc->mem_index, MO_TEUL); 1073d8e59c4aSRichard Henderson 1074d8e59c4aSRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail); 1075d8e59c4aSRichard Henderson tcg_temp_free_i32(tval); 1076d8e59c4aSRichard Henderson 1077d8e59c4aSRichard Henderson /* Success */ 1078d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1079d8e59c4aSRichard Henderson tcg_gen_br(swx_done); 1080d8e59c4aSRichard Henderson 1081d8e59c4aSRichard Henderson /* Failure */ 1082d8e59c4aSRichard Henderson gen_set_label(swx_fail); 1083d8e59c4aSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1084d8e59c4aSRichard Henderson 1085d8e59c4aSRichard Henderson gen_set_label(swx_done); 1086d8e59c4aSRichard Henderson 1087d8e59c4aSRichard Henderson /* 1088d8e59c4aSRichard Henderson * Prevent the saved address from working again without another ldx. 1089d8e59c4aSRichard Henderson * Akin to the pseudocode setting reservation = 0. 1090d8e59c4aSRichard Henderson */ 1091d8e59c4aSRichard Henderson tcg_gen_movi_tl(cpu_res_addr, -1); 1092d8e59c4aSRichard Henderson return true; 1093d8e59c4aSRichard Henderson } 1094d8e59c4aSRichard Henderson 109520800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 109620800179SRichard Henderson { 109720800179SRichard Henderson /* If opcode_0_illegal, trap. */ 109820800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 109920800179SRichard Henderson trap_illegal(dc, true); 110020800179SRichard Henderson return true; 110120800179SRichard Henderson } 110220800179SRichard Henderson /* 110320800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 110420800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 110520800179SRichard Henderson */ 110620800179SRichard Henderson return false; 110740cbf5b7SEdgar E. Iglesias } 11084acb54baSEdgar E. Iglesias 11091074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 11104acb54baSEdgar E. Iglesias { 11111074c0fbSRichard Henderson TCGv_i32 t; 11121074c0fbSRichard Henderson 11131074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 11141074c0fbSRichard Henderson t = tcg_temp_new_i32(); 11151074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 11161074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 11171074c0fbSRichard Henderson tcg_temp_free_i32(t); 11184acb54baSEdgar E. Iglesias } 11194acb54baSEdgar E. Iglesias 11201074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 11214acb54baSEdgar E. Iglesias { 11224acb54baSEdgar E. Iglesias dc->cpustate_changed = 1; 11231074c0fbSRichard Henderson 11241074c0fbSRichard Henderson /* Install MSR_C. */ 11251074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 11261074c0fbSRichard Henderson 11271074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 11281074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 11294acb54baSEdgar E. Iglesias } 11304acb54baSEdgar E. Iglesias 11314acb54baSEdgar E. Iglesias static void dec_msr(DisasContext *dc) 11324acb54baSEdgar E. Iglesias { 11330063ebd6SAndreas Färber CPUState *cs = CPU(dc->cpu); 1134cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 11352023e9a3SEdgar E. Iglesias unsigned int sr, rn; 1136f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 11374acb54baSEdgar E. Iglesias 11382023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 11392023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 11402023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 11414acb54baSEdgar E. Iglesias dc->type_b = 1; 11422023e9a3SEdgar E. Iglesias if (to) { 11434acb54baSEdgar E. Iglesias dc->cpustate_changed = 1; 1144f0f7e7f7SEdgar E. Iglesias } 1145f0f7e7f7SEdgar E. Iglesias 1146f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 1147f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 1148f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 1149f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 1150f0f7e7f7SEdgar E. Iglesias 1151f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 11522023e9a3SEdgar E. Iglesias } 11534acb54baSEdgar E. Iglesias 11544acb54baSEdgar E. Iglesias /* msrclr and msrset. */ 11552023e9a3SEdgar E. Iglesias if (clrset) { 11562023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 11574acb54baSEdgar E. Iglesias 115856837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 11591567a005SEdgar E. Iglesias /* nop??? */ 11601567a005SEdgar E. Iglesias return; 11611567a005SEdgar E. Iglesias } 11621567a005SEdgar E. Iglesias 1163bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 11641567a005SEdgar E. Iglesias return; 11651567a005SEdgar E. Iglesias } 11661567a005SEdgar E. Iglesias 11674acb54baSEdgar E. Iglesias if (dc->rd) 11684acb54baSEdgar E. Iglesias msr_read(dc, cpu_R[dc->rd]); 11694acb54baSEdgar E. Iglesias 1170cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1171cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 11724acb54baSEdgar E. Iglesias msr_read(dc, t0); 1173cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 11744acb54baSEdgar E. Iglesias 11754acb54baSEdgar E. Iglesias if (clr) { 1176cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 1177cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 11784acb54baSEdgar E. Iglesias } else 1179cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 11804acb54baSEdgar E. Iglesias msr_write(dc, t0); 1181cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1182cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1183d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 1184d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 11854acb54baSEdgar E. Iglesias return; 11864acb54baSEdgar E. Iglesias } 11874acb54baSEdgar E. Iglesias 1188bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 11891567a005SEdgar E. Iglesias return; 11901567a005SEdgar E. Iglesias } 11911567a005SEdgar E. Iglesias 11924acb54baSEdgar E. Iglesias #if !defined(CONFIG_USER_ONLY) 11934acb54baSEdgar E. Iglesias /* Catch read/writes to the mmu block. */ 11944acb54baSEdgar E. Iglesias if ((sr & ~0xff) == 0x1000) { 1195f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 119605a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 119705a9a651SEdgar E. Iglesias 11984acb54baSEdgar E. Iglesias sr &= 7; 119905a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 120005a9a651SEdgar E. Iglesias if (to) { 1201f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 120205a9a651SEdgar E. Iglesias } else { 1203f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 120405a9a651SEdgar E. Iglesias } 120505a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 1206f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 12074acb54baSEdgar E. Iglesias return; 12084acb54baSEdgar E. Iglesias } 12094acb54baSEdgar E. Iglesias #endif 12104acb54baSEdgar E. Iglesias 12114acb54baSEdgar E. Iglesias if (to) { 12124acb54baSEdgar E. Iglesias switch (sr) { 1213aa28e6d4SRichard Henderson case SR_PC: 12144acb54baSEdgar E. Iglesias break; 1215aa28e6d4SRichard Henderson case SR_MSR: 12164acb54baSEdgar E. Iglesias msr_write(dc, cpu_R[dc->ra]); 12174acb54baSEdgar E. Iglesias break; 1218351527b7SEdgar E. Iglesias case SR_EAR: 1219dbdb77c4SRichard Henderson { 1220dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1221dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 1222dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 1223dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1224dbdb77c4SRichard Henderson } 1225aa28e6d4SRichard Henderson break; 1226351527b7SEdgar E. Iglesias case SR_ESR: 122741ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 122841ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 1229aa28e6d4SRichard Henderson break; 1230ab6dd380SEdgar E. Iglesias case SR_FSR: 123186017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 123286017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 1233aa28e6d4SRichard Henderson break; 1234aa28e6d4SRichard Henderson case SR_BTR: 1235ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 1236ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 1237aa28e6d4SRichard Henderson break; 1238aa28e6d4SRichard Henderson case SR_EDR: 123939db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 124039db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 12414acb54baSEdgar E. Iglesias break; 12425818dee5SEdgar E. Iglesias case 0x800: 1243cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 1244cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 12455818dee5SEdgar E. Iglesias break; 12465818dee5SEdgar E. Iglesias case 0x802: 1247cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 1248cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 12495818dee5SEdgar E. Iglesias break; 12504acb54baSEdgar E. Iglesias default: 12510063ebd6SAndreas Färber cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 12524acb54baSEdgar E. Iglesias break; 12534acb54baSEdgar E. Iglesias } 12544acb54baSEdgar E. Iglesias } else { 12554acb54baSEdgar E. Iglesias switch (sr) { 1256aa28e6d4SRichard Henderson case SR_PC: 1257d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 12584acb54baSEdgar E. Iglesias break; 1259aa28e6d4SRichard Henderson case SR_MSR: 12604acb54baSEdgar E. Iglesias msr_read(dc, cpu_R[dc->rd]); 12614acb54baSEdgar E. Iglesias break; 1262351527b7SEdgar E. Iglesias case SR_EAR: 1263dbdb77c4SRichard Henderson { 1264dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 1265dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 1266a1b48e3aSEdgar E. Iglesias if (extended) { 1267dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 1268aa28e6d4SRichard Henderson } else { 1269dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 1270dbdb77c4SRichard Henderson } 1271dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 1272a1b48e3aSEdgar E. Iglesias } 1273aa28e6d4SRichard Henderson break; 1274351527b7SEdgar E. Iglesias case SR_ESR: 127541ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 127641ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 1277aa28e6d4SRichard Henderson break; 1278351527b7SEdgar E. Iglesias case SR_FSR: 127986017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 128086017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 1281aa28e6d4SRichard Henderson break; 1282351527b7SEdgar E. Iglesias case SR_BTR: 1283ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 1284ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 1285aa28e6d4SRichard Henderson break; 12867cdae31dSTong Ho case SR_EDR: 128739db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 128839db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 12894acb54baSEdgar E. Iglesias break; 12905818dee5SEdgar E. Iglesias case 0x800: 1291cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 1292cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 12935818dee5SEdgar E. Iglesias break; 12945818dee5SEdgar E. Iglesias case 0x802: 1295cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 1296cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 12975818dee5SEdgar E. Iglesias break; 1298351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 12994acb54baSEdgar E. Iglesias rn = sr & 0xf; 1300cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 130168cee38aSAndreas Färber cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 13024acb54baSEdgar E. Iglesias break; 13034acb54baSEdgar E. Iglesias default: 1304a47dddd7SAndreas Färber cpu_abort(cs, "unknown mfs reg %x\n", sr); 13054acb54baSEdgar E. Iglesias break; 13064acb54baSEdgar E. Iglesias } 13074acb54baSEdgar E. Iglesias } 1308ee7dbcf8SEdgar E. Iglesias 1309ee7dbcf8SEdgar E. Iglesias if (dc->rd == 0) { 1310cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 1311ee7dbcf8SEdgar E. Iglesias } 13124acb54baSEdgar E. Iglesias } 13134acb54baSEdgar E. Iglesias 13144acb54baSEdgar E. Iglesias static inline void eval_cc(DisasContext *dc, unsigned int cc, 13159e6e1828SEdgar E. Iglesias TCGv_i32 d, TCGv_i32 a) 13164acb54baSEdgar E. Iglesias { 1317d89b86e9SEdgar E. Iglesias static const int mb_to_tcg_cc[] = { 1318d89b86e9SEdgar E. Iglesias [CC_EQ] = TCG_COND_EQ, 1319d89b86e9SEdgar E. Iglesias [CC_NE] = TCG_COND_NE, 1320d89b86e9SEdgar E. Iglesias [CC_LT] = TCG_COND_LT, 1321d89b86e9SEdgar E. Iglesias [CC_LE] = TCG_COND_LE, 1322d89b86e9SEdgar E. Iglesias [CC_GE] = TCG_COND_GE, 1323d89b86e9SEdgar E. Iglesias [CC_GT] = TCG_COND_GT, 1324d89b86e9SEdgar E. Iglesias }; 1325d89b86e9SEdgar E. Iglesias 13264acb54baSEdgar E. Iglesias switch (cc) { 13274acb54baSEdgar E. Iglesias case CC_EQ: 13284acb54baSEdgar E. Iglesias case CC_NE: 13294acb54baSEdgar E. Iglesias case CC_LT: 13304acb54baSEdgar E. Iglesias case CC_LE: 13314acb54baSEdgar E. Iglesias case CC_GE: 13324acb54baSEdgar E. Iglesias case CC_GT: 13339e6e1828SEdgar E. Iglesias tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); 13344acb54baSEdgar E. Iglesias break; 13354acb54baSEdgar E. Iglesias default: 13360063ebd6SAndreas Färber cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); 13374acb54baSEdgar E. Iglesias break; 13384acb54baSEdgar E. Iglesias } 13394acb54baSEdgar E. Iglesias } 13404acb54baSEdgar E. Iglesias 13410f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) 13424acb54baSEdgar E. Iglesias { 13430f96e96bSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 1344e956caf2SEdgar E. Iglesias 13450f96e96bSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, 13469b158558SRichard Henderson cpu_btaken, zero, 1347e956caf2SEdgar E. Iglesias pc_true, pc_false); 1348e956caf2SEdgar E. Iglesias 13490f96e96bSRichard Henderson tcg_temp_free_i32(zero); 13504acb54baSEdgar E. Iglesias } 13514acb54baSEdgar E. Iglesias 1352f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1353f91c60f0SEdgar E. Iglesias { 1354f91c60f0SEdgar E. Iglesias dc->delayed_branch = 2; 1355f91c60f0SEdgar E. Iglesias dc->tb_flags |= D_FLAG; 1356*7b34f45fSRichard Henderson if (dc->type_b && (dc->tb_flags & IMM_FLAG)) { 1357*7b34f45fSRichard Henderson dc->tb_flags |= BIMM_FLAG; 1358*7b34f45fSRichard Henderson } 1359f91c60f0SEdgar E. Iglesias } 1360f91c60f0SEdgar E. Iglesias 13614acb54baSEdgar E. Iglesias static void dec_bcc(DisasContext *dc) 13624acb54baSEdgar E. Iglesias { 13634acb54baSEdgar E. Iglesias unsigned int cc; 13644acb54baSEdgar E. Iglesias unsigned int dslot; 13654acb54baSEdgar E. Iglesias 13664acb54baSEdgar E. Iglesias cc = EXTRACT_FIELD(dc->ir, 21, 23); 13674acb54baSEdgar E. Iglesias dslot = dc->ir & (1 << 25); 13684acb54baSEdgar E. Iglesias 13694acb54baSEdgar E. Iglesias dc->delayed_branch = 1; 13704acb54baSEdgar E. Iglesias if (dslot) { 1371f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 13724acb54baSEdgar E. Iglesias } 13734acb54baSEdgar E. Iglesias 1374d7ecb757SRichard Henderson if (dc->type_b) { 1375844bab60SEdgar E. Iglesias dc->jmp = JMP_DIRECT_CC; 1376d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1377d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 137861204ce8SEdgar E. Iglesias } else { 137923979dc5SEdgar E. Iglesias dc->jmp = JMP_INDIRECT; 1380d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 138161204ce8SEdgar E. Iglesias } 13829b158558SRichard Henderson eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); 13834acb54baSEdgar E. Iglesias } 13844acb54baSEdgar E. Iglesias 13854acb54baSEdgar E. Iglesias static void dec_br(DisasContext *dc) 13864acb54baSEdgar E. Iglesias { 13879f6113c7SEdgar E. Iglesias unsigned int dslot, link, abs, mbar; 13884acb54baSEdgar E. Iglesias 13894acb54baSEdgar E. Iglesias dslot = dc->ir & (1 << 20); 13904acb54baSEdgar E. Iglesias abs = dc->ir & (1 << 19); 13914acb54baSEdgar E. Iglesias link = dc->ir & (1 << 18); 13929f6113c7SEdgar E. Iglesias 13939f6113c7SEdgar E. Iglesias /* Memory barrier. */ 13949f6113c7SEdgar E. Iglesias mbar = (dc->ir >> 16) & 31; 13959f6113c7SEdgar E. Iglesias if (mbar == 2 && dc->imm == 4) { 1396badcbf9dSEdgar E. Iglesias uint16_t mbar_imm = dc->rd; 1397badcbf9dSEdgar E. Iglesias 13983f172744SEdgar E. Iglesias /* Data access memory barrier. */ 13993f172744SEdgar E. Iglesias if ((mbar_imm & 2) == 0) { 14003f172744SEdgar E. Iglesias tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 14013f172744SEdgar E. Iglesias } 14023f172744SEdgar E. Iglesias 14035d45de97SEdgar E. Iglesias /* mbar IMM & 16 decodes to sleep. */ 1404badcbf9dSEdgar E. Iglesias if (mbar_imm & 16) { 140541ba37c4SRichard Henderson TCGv_i32 tmp_1; 14065d45de97SEdgar E. Iglesias 1407b4919e7dSEdgar E. Iglesias if (trap_userspace(dc, true)) { 1408b4919e7dSEdgar E. Iglesias /* Sleep is a privileged instruction. */ 1409b4919e7dSEdgar E. Iglesias return; 1410b4919e7dSEdgar E. Iglesias } 1411b4919e7dSEdgar E. Iglesias 14125d45de97SEdgar E. Iglesias t_sync_flags(dc); 141341ba37c4SRichard Henderson 141441ba37c4SRichard Henderson tmp_1 = tcg_const_i32(1); 14155d45de97SEdgar E. Iglesias tcg_gen_st_i32(tmp_1, cpu_env, 14165d45de97SEdgar E. Iglesias -offsetof(MicroBlazeCPU, env) 14175d45de97SEdgar E. Iglesias +offsetof(CPUState, halted)); 14185d45de97SEdgar E. Iglesias tcg_temp_free_i32(tmp_1); 141941ba37c4SRichard Henderson 1420d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 142141ba37c4SRichard Henderson 142241ba37c4SRichard Henderson gen_raise_exception(dc, EXCP_HLT); 14235d45de97SEdgar E. Iglesias return; 14245d45de97SEdgar E. Iglesias } 14259f6113c7SEdgar E. Iglesias /* Break the TB. */ 14269f6113c7SEdgar E. Iglesias dc->cpustate_changed = 1; 14279f6113c7SEdgar E. Iglesias return; 14289f6113c7SEdgar E. Iglesias } 14299f6113c7SEdgar E. Iglesias 1430d7ecb757SRichard Henderson if (abs && link && !dslot) { 1431d7ecb757SRichard Henderson if (dc->type_b) { 1432d7ecb757SRichard Henderson /* BRKI */ 1433d7ecb757SRichard Henderson uint32_t imm = dec_alu_typeb_imm(dc); 1434d7ecb757SRichard Henderson if (trap_userspace(dc, imm != 8 && imm != 0x18)) { 1435d7ecb757SRichard Henderson return; 1436d7ecb757SRichard Henderson } 1437d7ecb757SRichard Henderson } else { 1438d7ecb757SRichard Henderson /* BRK */ 1439d7ecb757SRichard Henderson if (trap_userspace(dc, true)) { 1440d7ecb757SRichard Henderson return; 1441d7ecb757SRichard Henderson } 1442d7ecb757SRichard Henderson } 1443d7ecb757SRichard Henderson } 1444d7ecb757SRichard Henderson 14454acb54baSEdgar E. Iglesias dc->delayed_branch = 1; 14464acb54baSEdgar E. Iglesias if (dslot) { 1447f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 14484acb54baSEdgar E. Iglesias } 1449d7ecb757SRichard Henderson if (link && dc->rd) { 1450d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1451d7ecb757SRichard Henderson } 14524acb54baSEdgar E. Iglesias 14534acb54baSEdgar E. Iglesias if (abs) { 1454d7ecb757SRichard Henderson if (dc->type_b) { 1455d7ecb757SRichard Henderson uint32_t dest = dec_alu_typeb_imm(dc); 1456d7ecb757SRichard Henderson 1457d7ecb757SRichard Henderson dc->jmp = JMP_DIRECT; 1458d7ecb757SRichard Henderson dc->jmp_pc = dest; 1459d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dest); 1460ff21f70aSEdgar E. Iglesias if (link && !dslot) { 1461d7ecb757SRichard Henderson switch (dest) { 1462d7ecb757SRichard Henderson case 8: 1463d7ecb757SRichard Henderson case 0x18: 1464d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 1465d7ecb757SRichard Henderson break; 1466d7ecb757SRichard Henderson case 0: 1467d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1468d7ecb757SRichard Henderson break; 1469d7ecb757SRichard Henderson } 1470d7ecb757SRichard Henderson } 1471d7ecb757SRichard Henderson } else { 1472d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1473d7ecb757SRichard Henderson tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]); 1474d7ecb757SRichard Henderson if (link && !dslot) { 147541ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 147641ba37c4SRichard Henderson } 1477ff21f70aSEdgar E. Iglesias } 1478d7ecb757SRichard Henderson } else if (dc->type_b) { 147961204ce8SEdgar E. Iglesias dc->jmp = JMP_DIRECT; 1480d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1481d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 148261204ce8SEdgar E. Iglesias } else { 1483d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1484d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1485d7ecb757SRichard Henderson } 14869b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 14874acb54baSEdgar E. Iglesias } 14884acb54baSEdgar E. Iglesias 14894acb54baSEdgar E. Iglesias static inline void do_rti(DisasContext *dc) 14904acb54baSEdgar E. Iglesias { 1491cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1492cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1493cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 14943e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 14950a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 14960a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1497cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 14984acb54baSEdgar E. Iglesias 1499cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1500cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 15014acb54baSEdgar E. Iglesias msr_write(dc, t1); 1502cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1503cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 15044acb54baSEdgar E. Iglesias dc->tb_flags &= ~DRTI_FLAG; 15054acb54baSEdgar E. Iglesias } 15064acb54baSEdgar E. Iglesias 15074acb54baSEdgar E. Iglesias static inline void do_rtb(DisasContext *dc) 15084acb54baSEdgar E. Iglesias { 1509cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1510cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1511cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 15123e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 15130a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1514cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1515cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 15164acb54baSEdgar E. Iglesias 1517cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1518cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 15194acb54baSEdgar E. Iglesias msr_write(dc, t1); 1520cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1521cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 15224acb54baSEdgar E. Iglesias dc->tb_flags &= ~DRTB_FLAG; 15234acb54baSEdgar E. Iglesias } 15244acb54baSEdgar E. Iglesias 15254acb54baSEdgar E. Iglesias static inline void do_rte(DisasContext *dc) 15264acb54baSEdgar E. Iglesias { 1527cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1528cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1529cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 15304acb54baSEdgar E. Iglesias 15313e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 15320a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1533cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1534cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1535cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 15364acb54baSEdgar E. Iglesias 1537cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1538cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 15394acb54baSEdgar E. Iglesias msr_write(dc, t1); 1540cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1541cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 15424acb54baSEdgar E. Iglesias dc->tb_flags &= ~DRTE_FLAG; 15434acb54baSEdgar E. Iglesias } 15444acb54baSEdgar E. Iglesias 15454acb54baSEdgar E. Iglesias static void dec_rts(DisasContext *dc) 15464acb54baSEdgar E. Iglesias { 15474acb54baSEdgar E. Iglesias unsigned int b_bit, i_bit, e_bit; 15484acb54baSEdgar E. Iglesias 15494acb54baSEdgar E. Iglesias i_bit = dc->ir & (1 << 21); 15504acb54baSEdgar E. Iglesias b_bit = dc->ir & (1 << 22); 15514acb54baSEdgar E. Iglesias e_bit = dc->ir & (1 << 23); 15524acb54baSEdgar E. Iglesias 1553bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1554bdfc1e88SEdgar E. Iglesias return; 1555bdfc1e88SEdgar E. Iglesias } 1556bdfc1e88SEdgar E. Iglesias 1557f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 15584acb54baSEdgar E. Iglesias 15594acb54baSEdgar E. Iglesias if (i_bit) { 15604acb54baSEdgar E. Iglesias dc->tb_flags |= DRTI_FLAG; 15614acb54baSEdgar E. Iglesias } else if (b_bit) { 15624acb54baSEdgar E. Iglesias dc->tb_flags |= DRTB_FLAG; 15634acb54baSEdgar E. Iglesias } else if (e_bit) { 15644acb54baSEdgar E. Iglesias dc->tb_flags |= DRTE_FLAG; 156511105d67SRichard Henderson } 15664acb54baSEdgar E. Iglesias 156723979dc5SEdgar E. Iglesias dc->jmp = JMP_INDIRECT; 15689b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 15690f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 15704acb54baSEdgar E. Iglesias } 15714acb54baSEdgar E. Iglesias 15724acb54baSEdgar E. Iglesias static void dec_null(DisasContext *dc) 15734acb54baSEdgar E. Iglesias { 15749ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 157502b33596SEdgar E. Iglesias return; 157602b33596SEdgar E. Iglesias } 1577d4705ae0SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", 1578d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, dc->opcode); 15794acb54baSEdgar E. Iglesias dc->abort_at_next_insn = 1; 15804acb54baSEdgar E. Iglesias } 15814acb54baSEdgar E. Iglesias 15826d76d23eSEdgar E. Iglesias /* Insns connected to FSL or AXI stream attached devices. */ 15836d76d23eSEdgar E. Iglesias static void dec_stream(DisasContext *dc) 15846d76d23eSEdgar E. Iglesias { 15856d76d23eSEdgar E. Iglesias TCGv_i32 t_id, t_ctrl; 15866d76d23eSEdgar E. Iglesias int ctrl; 15876d76d23eSEdgar E. Iglesias 1588bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 15896d76d23eSEdgar E. Iglesias return; 15906d76d23eSEdgar E. Iglesias } 15916d76d23eSEdgar E. Iglesias 1592cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 15936d76d23eSEdgar E. Iglesias if (dc->type_b) { 1594cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 15956d76d23eSEdgar E. Iglesias ctrl = dc->imm >> 10; 15966d76d23eSEdgar E. Iglesias } else { 1597cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 15986d76d23eSEdgar E. Iglesias ctrl = dc->imm >> 5; 15996d76d23eSEdgar E. Iglesias } 16006d76d23eSEdgar E. Iglesias 1601cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 16026d76d23eSEdgar E. Iglesias 16036d76d23eSEdgar E. Iglesias if (dc->rd == 0) { 16046d76d23eSEdgar E. Iglesias gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 16056d76d23eSEdgar E. Iglesias } else { 16066d76d23eSEdgar E. Iglesias gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 16076d76d23eSEdgar E. Iglesias } 1608cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1609cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 16106d76d23eSEdgar E. Iglesias } 16116d76d23eSEdgar E. Iglesias 16124acb54baSEdgar E. Iglesias static struct decoder_info { 16134acb54baSEdgar E. Iglesias struct { 16144acb54baSEdgar E. Iglesias uint32_t bits; 16154acb54baSEdgar E. Iglesias uint32_t mask; 16164acb54baSEdgar E. Iglesias }; 16174acb54baSEdgar E. Iglesias void (*dec)(DisasContext *dc); 16184acb54baSEdgar E. Iglesias } decinfo[] = { 16194acb54baSEdgar E. Iglesias {DEC_BR, dec_br}, 16204acb54baSEdgar E. Iglesias {DEC_BCC, dec_bcc}, 16214acb54baSEdgar E. Iglesias {DEC_RTS, dec_rts}, 16224acb54baSEdgar E. Iglesias {DEC_MSR, dec_msr}, 16236d76d23eSEdgar E. Iglesias {DEC_STREAM, dec_stream}, 16244acb54baSEdgar E. Iglesias {{0, 0}, dec_null} 16254acb54baSEdgar E. Iglesias }; 16264acb54baSEdgar E. Iglesias 162744d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir) 16284acb54baSEdgar E. Iglesias { 16294acb54baSEdgar E. Iglesias int i; 16304acb54baSEdgar E. Iglesias 163164254ebaSBlue Swirl dc->ir = ir; 16324acb54baSEdgar E. Iglesias 16334acb54baSEdgar E. Iglesias /* bit 2 seems to indicate insn type. */ 16344acb54baSEdgar E. Iglesias dc->type_b = ir & (1 << 29); 16354acb54baSEdgar E. Iglesias 16364acb54baSEdgar E. Iglesias dc->opcode = EXTRACT_FIELD(ir, 26, 31); 16374acb54baSEdgar E. Iglesias dc->rd = EXTRACT_FIELD(ir, 21, 25); 16384acb54baSEdgar E. Iglesias dc->ra = EXTRACT_FIELD(ir, 16, 20); 16394acb54baSEdgar E. Iglesias dc->rb = EXTRACT_FIELD(ir, 11, 15); 16404acb54baSEdgar E. Iglesias dc->imm = EXTRACT_FIELD(ir, 0, 15); 16414acb54baSEdgar E. Iglesias 16424acb54baSEdgar E. Iglesias /* Large switch for all insns. */ 16434acb54baSEdgar E. Iglesias for (i = 0; i < ARRAY_SIZE(decinfo); i++) { 16444acb54baSEdgar E. Iglesias if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { 16454acb54baSEdgar E. Iglesias decinfo[i].dec(dc); 16464acb54baSEdgar E. Iglesias break; 16474acb54baSEdgar E. Iglesias } 16484acb54baSEdgar E. Iglesias } 16494acb54baSEdgar E. Iglesias } 16504acb54baSEdgar E. Iglesias 1651372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 16524acb54baSEdgar E. Iglesias { 1653372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1654372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1655372122e3SRichard Henderson int bound; 16564acb54baSEdgar E. Iglesias 16570063ebd6SAndreas Färber dc->cpu = cpu; 1658372122e3SRichard Henderson dc->synced_flags = dc->tb_flags = dc->base.tb->flags; 16594acb54baSEdgar E. Iglesias dc->delayed_branch = !!(dc->tb_flags & D_FLAG); 1660372122e3SRichard Henderson dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; 16614acb54baSEdgar E. Iglesias dc->cpustate_changed = 0; 16624acb54baSEdgar E. Iglesias dc->abort_at_next_insn = 0; 1663d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 166420800179SRichard Henderson dc->r0 = NULL; 166520800179SRichard Henderson dc->r0_set = false; 1666287b1defSRichard Henderson dc->mem_index = cpu_mmu_index(&cpu->env, false); 16674acb54baSEdgar E. Iglesias 1668372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1669372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1670a47dddd7SAndreas Färber } 16714acb54baSEdgar E. Iglesias 1672372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 16734acb54baSEdgar E. Iglesias { 1674b933066aSRichard Henderson } 1675b933066aSRichard Henderson 1676372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1677372122e3SRichard Henderson { 1678372122e3SRichard Henderson tcg_gen_insn_start(dcb->pc_next); 1679372122e3SRichard Henderson } 16804acb54baSEdgar E. Iglesias 1681372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1682372122e3SRichard Henderson const CPUBreakpoint *bp) 1683372122e3SRichard Henderson { 1684372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1685372122e3SRichard Henderson 1686372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1687372122e3SRichard Henderson 1688372122e3SRichard Henderson /* 1689372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1690372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1691372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1692372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1693372122e3SRichard Henderson */ 1694372122e3SRichard Henderson dc->base.pc_next += 4; 1695372122e3SRichard Henderson return true; 1696372122e3SRichard Henderson } 1697372122e3SRichard Henderson 1698372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1699372122e3SRichard Henderson { 1700372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1701372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 170244d1432bSRichard Henderson uint32_t ir; 1703372122e3SRichard Henderson 1704372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1705372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1706372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1707372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1708959082fcSRichard Henderson } 17094acb54baSEdgar E. Iglesias 17104acb54baSEdgar E. Iglesias dc->clear_imm = 1; 171144d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 171244d1432bSRichard Henderson if (!decode(dc, ir)) { 171344d1432bSRichard Henderson old_decode(dc, ir); 171444d1432bSRichard Henderson } 171520800179SRichard Henderson 171620800179SRichard Henderson if (dc->r0) { 171720800179SRichard Henderson tcg_temp_free_i32(dc->r0); 171820800179SRichard Henderson dc->r0 = NULL; 171920800179SRichard Henderson dc->r0_set = false; 172020800179SRichard Henderson } 172120800179SRichard Henderson 1722d7ecb757SRichard Henderson if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { 17234acb54baSEdgar E. Iglesias dc->tb_flags &= ~IMM_FLAG; 1724d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1725372122e3SRichard Henderson } 1726d4705ae0SRichard Henderson dc->base.pc_next += 4; 17274acb54baSEdgar E. Iglesias 1728372122e3SRichard Henderson if (dc->delayed_branch && --dc->delayed_branch == 0) { 1729372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 17304acb54baSEdgar E. Iglesias do_rti(dc); 1731372122e3SRichard Henderson } 1732372122e3SRichard Henderson if (dc->tb_flags & DRTB_FLAG) { 17334acb54baSEdgar E. Iglesias do_rtb(dc); 1734372122e3SRichard Henderson } 1735372122e3SRichard Henderson if (dc->tb_flags & DRTE_FLAG) { 17364acb54baSEdgar E. Iglesias do_rte(dc); 1737372122e3SRichard Henderson } 17384acb54baSEdgar E. Iglesias /* Clear the delay slot flag. */ 17394acb54baSEdgar E. Iglesias dc->tb_flags &= ~D_FLAG; 1740372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1741372122e3SRichard Henderson } 1742372122e3SRichard Henderson 1743372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1744372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1745372122e3SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1746372122e3SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1747372122e3SRichard Henderson } 1748372122e3SRichard Henderson } 1749372122e3SRichard Henderson 1750372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1751372122e3SRichard Henderson { 1752372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1753372122e3SRichard Henderson 1754372122e3SRichard Henderson assert(!dc->abort_at_next_insn); 1755372122e3SRichard Henderson 1756372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1757372122e3SRichard Henderson /* We have already exited the TB. */ 1758372122e3SRichard Henderson return; 1759372122e3SRichard Henderson } 1760372122e3SRichard Henderson 1761372122e3SRichard Henderson t_sync_flags(dc); 1762372122e3SRichard Henderson if (dc->tb_flags & D_FLAG) { 1763372122e3SRichard Henderson sync_jmpstate(dc); 1764372122e3SRichard Henderson dc->jmp = JMP_NOJMP; 1765372122e3SRichard Henderson } 1766372122e3SRichard Henderson 1767372122e3SRichard Henderson switch (dc->base.is_jmp) { 1768372122e3SRichard Henderson case DISAS_TOO_MANY: 1769372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1770372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1771372122e3SRichard Henderson return; 1772372122e3SRichard Henderson 1773372122e3SRichard Henderson case DISAS_UPDATE: 1774372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1775372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1776372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1777372122e3SRichard Henderson } else { 1778372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1779372122e3SRichard Henderson } 1780372122e3SRichard Henderson return; 1781372122e3SRichard Henderson 1782372122e3SRichard Henderson case DISAS_JUMP: 1783372122e3SRichard Henderson switch (dc->jmp) { 1784372122e3SRichard Henderson case JMP_INDIRECT: 1785372122e3SRichard Henderson { 1786d4705ae0SRichard Henderson TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); 17870f96e96bSRichard Henderson eval_cond_jmp(dc, cpu_btarget, tmp_pc); 17880f96e96bSRichard Henderson tcg_temp_free_i32(tmp_pc); 1789372122e3SRichard Henderson 1790372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1791372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1792372122e3SRichard Henderson } else { 1793372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1794372122e3SRichard Henderson } 1795372122e3SRichard Henderson } 1796372122e3SRichard Henderson return; 1797372122e3SRichard Henderson 1798372122e3SRichard Henderson case JMP_DIRECT_CC: 1799372122e3SRichard Henderson { 180042a268c2SRichard Henderson TCGLabel *l1 = gen_new_label(); 18019b158558SRichard Henderson tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); 1802d4705ae0SRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 180323979dc5SEdgar E. Iglesias gen_set_label(l1); 1804372122e3SRichard Henderson } 1805372122e3SRichard Henderson /* fall through */ 1806372122e3SRichard Henderson 1807372122e3SRichard Henderson case JMP_DIRECT: 180823979dc5SEdgar E. Iglesias gen_goto_tb(dc, 0, dc->jmp_pc); 1809372122e3SRichard Henderson return; 18104acb54baSEdgar E. Iglesias } 1811372122e3SRichard Henderson /* fall through */ 18124acb54baSEdgar E. Iglesias 1813a2b80dbdSRichard Henderson default: 1814a2b80dbdSRichard Henderson g_assert_not_reached(); 18154acb54baSEdgar E. Iglesias } 18164acb54baSEdgar E. Iglesias } 18170a7df5daSRichard Henderson 1818372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1819372122e3SRichard Henderson { 1820372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1821372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 18224acb54baSEdgar E. Iglesias } 1823372122e3SRichard Henderson 1824372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1825372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1826372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1827372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1828372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1829372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1830372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1831372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1832372122e3SRichard Henderson }; 1833372122e3SRichard Henderson 1834372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1835372122e3SRichard Henderson { 1836372122e3SRichard Henderson DisasContext dc; 1837372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 18384acb54baSEdgar E. Iglesias } 18394acb54baSEdgar E. Iglesias 184090c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 18414acb54baSEdgar E. Iglesias { 1842878096eeSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1843878096eeSAndreas Färber CPUMBState *env = &cpu->env; 18444acb54baSEdgar E. Iglesias int i; 18454acb54baSEdgar E. Iglesias 184690c84c56SMarkus Armbruster if (!env) { 18474acb54baSEdgar E. Iglesias return; 184890c84c56SMarkus Armbruster } 18494acb54baSEdgar E. Iglesias 18500f96e96bSRichard Henderson qemu_fprintf(f, "IN: PC=%x %s\n", 185176e8187dSRichard Henderson env->pc, lookup_symbol(env->pc)); 18526efd5599SRichard Henderson qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " 1853eb2022b7SRichard Henderson "imm=%x iflags=%x fsr=%x rbtr=%x\n", 185478e9caf2SRichard Henderson env->msr, env->esr, env->ear, 1855eb2022b7SRichard Henderson env->imm, env->iflags, env->fsr, env->btr); 18560f96e96bSRichard Henderson qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 18574acb54baSEdgar E. Iglesias env->btaken, env->btarget, 18582e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18592e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18602e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18612e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18622ead1b18SJoe Komlodi for (i = 0; i < 12; i++) { 18632ead1b18SJoe Komlodi qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); 18642ead1b18SJoe Komlodi if ((i + 1) % 4 == 0) { 18652ead1b18SJoe Komlodi qemu_fprintf(f, "\n"); 18662ead1b18SJoe Komlodi } 18672ead1b18SJoe Komlodi } 186817c52a43SEdgar E. Iglesias 18692ead1b18SJoe Komlodi /* Registers that aren't modeled are reported as 0 */ 187039db007eSRichard Henderson qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " 1871af20a93aSRichard Henderson "rtlblo=0 rtlbhi=0\n", env->edr); 18722ead1b18SJoe Komlodi qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); 18734acb54baSEdgar E. Iglesias for (i = 0; i < 32; i++) { 187490c84c56SMarkus Armbruster qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); 18754acb54baSEdgar E. Iglesias if ((i + 1) % 4 == 0) 187690c84c56SMarkus Armbruster qemu_fprintf(f, "\n"); 18774acb54baSEdgar E. Iglesias } 187890c84c56SMarkus Armbruster qemu_fprintf(f, "\n\n"); 18794acb54baSEdgar E. Iglesias } 18804acb54baSEdgar E. Iglesias 1881cd0c24f9SAndreas Färber void mb_tcg_init(void) 1882cd0c24f9SAndreas Färber { 1883480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1884480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 18854acb54baSEdgar E. Iglesias 1886480d29a8SRichard Henderson static const struct { 1887480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1888480d29a8SRichard Henderson } i32s[] = { 1889480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1890480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1891480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1892480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1893480d29a8SRichard Henderson 1894480d29a8SRichard Henderson SP(pc), 1895480d29a8SRichard Henderson SP(msr), 18961074c0fbSRichard Henderson SP(msr_c), 1897480d29a8SRichard Henderson SP(imm), 1898480d29a8SRichard Henderson SP(iflags), 1899480d29a8SRichard Henderson SP(btaken), 1900480d29a8SRichard Henderson SP(btarget), 1901480d29a8SRichard Henderson SP(res_val), 1902480d29a8SRichard Henderson }; 1903480d29a8SRichard Henderson 1904480d29a8SRichard Henderson #undef R 1905480d29a8SRichard Henderson #undef SP 1906480d29a8SRichard Henderson 1907480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1908480d29a8SRichard Henderson *i32s[i].var = 1909480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 19104acb54baSEdgar E. Iglesias } 191176e8187dSRichard Henderson 1912480d29a8SRichard Henderson cpu_res_addr = 1913480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 19144acb54baSEdgar E. Iglesias } 19154acb54baSEdgar E. Iglesias 1916bad729e2SRichard Henderson void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1917bad729e2SRichard Henderson target_ulong *data) 19184acb54baSEdgar E. Iglesias { 191976e8187dSRichard Henderson env->pc = data[0]; 19204acb54baSEdgar E. Iglesias } 1921