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; 764acb54baSEdgar E. Iglesias 774acb54baSEdgar E. Iglesias #define JMP_NOJMP 0 784acb54baSEdgar E. Iglesias #define JMP_DIRECT 1 79844bab60SEdgar E. Iglesias #define JMP_DIRECT_CC 2 80844bab60SEdgar E. Iglesias #define JMP_INDIRECT 3 814acb54baSEdgar E. Iglesias unsigned int jmp; 824acb54baSEdgar E. Iglesias uint32_t jmp_pc; 834acb54baSEdgar E. Iglesias 844acb54baSEdgar E. Iglesias int abort_at_next_insn; 854acb54baSEdgar E. Iglesias } DisasContext; 864acb54baSEdgar E. Iglesias 8720800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 8820800179SRichard Henderson { 8920800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 9020800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 9120800179SRichard Henderson } 9220800179SRichard Henderson return x; 9320800179SRichard Henderson } 9420800179SRichard Henderson 9544d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9644d1432bSRichard Henderson #include "decode-insns.c.inc" 9744d1432bSRichard Henderson 984acb54baSEdgar E. Iglesias static inline void t_sync_flags(DisasContext *dc) 994acb54baSEdgar E. Iglesias { 1004abf79a4SDong Xu Wang /* Synch the tb dependent flags between translator and runtime. */ 1014acb54baSEdgar E. Iglesias if (dc->tb_flags != dc->synced_flags) { 1029b158558SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags); 1034acb54baSEdgar E. Iglesias dc->synced_flags = dc->tb_flags; 1044acb54baSEdgar E. Iglesias } 1054acb54baSEdgar E. Iglesias } 1064acb54baSEdgar E. Iglesias 10741ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 1084acb54baSEdgar E. Iglesias { 1094acb54baSEdgar E. Iglesias TCGv_i32 tmp = tcg_const_i32(index); 1104acb54baSEdgar E. Iglesias 11164254ebaSBlue Swirl gen_helper_raise_exception(cpu_env, tmp); 1124acb54baSEdgar E. Iglesias tcg_temp_free_i32(tmp); 113d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 1144acb54baSEdgar E. Iglesias } 1154acb54baSEdgar E. Iglesias 11641ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11741ba37c4SRichard Henderson { 11841ba37c4SRichard Henderson t_sync_flags(dc); 119d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 12041ba37c4SRichard Henderson gen_raise_exception(dc, index); 12141ba37c4SRichard Henderson } 12241ba37c4SRichard Henderson 12341ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12441ba37c4SRichard Henderson { 12541ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12641ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12741ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12841ba37c4SRichard Henderson 12941ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 13041ba37c4SRichard Henderson } 13141ba37c4SRichard Henderson 13290aa39a1SSergey Fedorov static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 13390aa39a1SSergey Fedorov { 13490aa39a1SSergey Fedorov #ifndef CONFIG_USER_ONLY 135d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 13690aa39a1SSergey Fedorov #else 13790aa39a1SSergey Fedorov return true; 13890aa39a1SSergey Fedorov #endif 13990aa39a1SSergey Fedorov } 14090aa39a1SSergey Fedorov 1414acb54baSEdgar E. Iglesias static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 1424acb54baSEdgar E. Iglesias { 143d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1440b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1450b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1460b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1470b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1480b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 1494acb54baSEdgar E. Iglesias tcg_gen_goto_tb(n); 1500f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 151d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 1524acb54baSEdgar E. Iglesias } else { 1530f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 15407ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1554acb54baSEdgar E. Iglesias } 156d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 1574acb54baSEdgar E. Iglesias } 1584acb54baSEdgar E. Iglesias 159bdfc1e88SEdgar E. Iglesias /* 1609ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1619ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1629ba8cd45SEdgar E. Iglesias */ 1639ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1649ba8cd45SEdgar E. Iglesias { 1659ba8cd45SEdgar E. Iglesias if (cond && (dc->tb_flags & MSR_EE_FLAG) 1665143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 16741ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1689ba8cd45SEdgar E. Iglesias } 1699ba8cd45SEdgar E. Iglesias return cond; 1709ba8cd45SEdgar E. Iglesias } 1719ba8cd45SEdgar E. Iglesias 1729ba8cd45SEdgar E. Iglesias /* 173bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 174bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 175bdfc1e88SEdgar E. Iglesias */ 176bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 177bdfc1e88SEdgar E. Iglesias { 178bdfc1e88SEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 179bdfc1e88SEdgar E. Iglesias bool cond_user = cond && mem_index == MMU_USER_IDX; 180bdfc1e88SEdgar E. Iglesias 181bdfc1e88SEdgar E. Iglesias if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { 18241ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 183bdfc1e88SEdgar E. Iglesias } 184bdfc1e88SEdgar E. Iglesias return cond_user; 185bdfc1e88SEdgar E. Iglesias } 186bdfc1e88SEdgar E. Iglesias 187d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc) 18861204ce8SEdgar E. Iglesias { 189d7ecb757SRichard Henderson tcg_debug_assert(dc->type_b); 19020800179SRichard Henderson return typeb_imm(dc, (int16_t)dc->imm); 19161204ce8SEdgar E. Iglesias } 19261204ce8SEdgar E. Iglesias 193cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) 1944acb54baSEdgar E. Iglesias { 1954acb54baSEdgar E. Iglesias if (dc->type_b) { 196d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc)); 1979b158558SRichard Henderson return &cpu_imm; 198d7ecb757SRichard Henderson } 1994acb54baSEdgar E. Iglesias return &cpu_R[dc->rb]; 2004acb54baSEdgar E. Iglesias } 2014acb54baSEdgar E. Iglesias 20220800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 2034acb54baSEdgar E. Iglesias { 20420800179SRichard Henderson if (likely(reg != 0)) { 20520800179SRichard Henderson return cpu_R[reg]; 2064acb54baSEdgar E. Iglesias } 20720800179SRichard Henderson if (!dc->r0_set) { 20820800179SRichard Henderson if (dc->r0 == NULL) { 20920800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 2104acb54baSEdgar E. Iglesias } 21120800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 21220800179SRichard Henderson dc->r0_set = true; 21320800179SRichard Henderson } 21420800179SRichard Henderson return dc->r0; 21540cbf5b7SEdgar E. Iglesias } 21640cbf5b7SEdgar E. Iglesias 21720800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 21820800179SRichard Henderson { 21920800179SRichard Henderson if (likely(reg != 0)) { 22020800179SRichard Henderson return cpu_R[reg]; 22120800179SRichard Henderson } 22220800179SRichard Henderson if (dc->r0 == NULL) { 22320800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 22420800179SRichard Henderson } 22520800179SRichard Henderson return dc->r0; 22640cbf5b7SEdgar E. Iglesias } 22740cbf5b7SEdgar E. Iglesias 22820800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 22920800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 23020800179SRichard Henderson { 23120800179SRichard Henderson TCGv_i32 rd, ra, rb; 23220800179SRichard Henderson 23320800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 23420800179SRichard Henderson return true; 23540cbf5b7SEdgar E. Iglesias } 23620800179SRichard Henderson 23720800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 23820800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 23920800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 24020800179SRichard Henderson fn(rd, ra, rb); 24120800179SRichard Henderson return true; 24220800179SRichard Henderson } 24320800179SRichard Henderson 24420800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 24520800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 24620800179SRichard Henderson { 24720800179SRichard Henderson TCGv_i32 rd, ra; 24820800179SRichard Henderson 24920800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 25020800179SRichard Henderson return true; 25120800179SRichard Henderson } 25220800179SRichard Henderson 25320800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 25420800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 25520800179SRichard Henderson fni(rd, ra, arg->imm); 25620800179SRichard Henderson return true; 25720800179SRichard Henderson } 25820800179SRichard Henderson 25920800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 26020800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 26120800179SRichard Henderson { 26220800179SRichard Henderson TCGv_i32 rd, ra, imm; 26320800179SRichard Henderson 26420800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 26520800179SRichard Henderson return true; 26620800179SRichard Henderson } 26720800179SRichard Henderson 26820800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 26920800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 27020800179SRichard Henderson imm = tcg_const_i32(arg->imm); 27120800179SRichard Henderson 27220800179SRichard Henderson fn(rd, ra, imm); 27320800179SRichard Henderson 27420800179SRichard Henderson tcg_temp_free_i32(imm); 27520800179SRichard Henderson return true; 27620800179SRichard Henderson } 27720800179SRichard Henderson 27820800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 27920800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 28020800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 28120800179SRichard Henderson 28220800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 28320800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 28420800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 28520800179SRichard Henderson 28620800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 28720800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 28820800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 28920800179SRichard Henderson 29020800179SRichard Henderson /* No input carry, but output carry. */ 29120800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 29220800179SRichard Henderson { 29320800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 29420800179SRichard Henderson 29520800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 29620800179SRichard Henderson 29720800179SRichard Henderson tcg_temp_free_i32(zero); 29820800179SRichard Henderson } 29920800179SRichard Henderson 30020800179SRichard Henderson /* Input and output carry. */ 30120800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 30220800179SRichard Henderson { 30320800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 30420800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 30520800179SRichard Henderson 30620800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 30720800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 30820800179SRichard Henderson 30920800179SRichard Henderson tcg_temp_free_i32(tmp); 31020800179SRichard Henderson tcg_temp_free_i32(zero); 31120800179SRichard Henderson } 31220800179SRichard Henderson 31320800179SRichard Henderson /* Input carry, but no output carry. */ 31420800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 31520800179SRichard Henderson { 31620800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 31720800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 31820800179SRichard Henderson } 31920800179SRichard Henderson 32020800179SRichard Henderson DO_TYPEA(add, true, gen_add) 32120800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 32220800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 32320800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 32420800179SRichard Henderson 32520800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 32620800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 32720800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 32820800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 32920800179SRichard Henderson 330*a2b0b90eSRichard Henderson DO_TYPEA(cmp, false, gen_helper_cmp) 331*a2b0b90eSRichard Henderson DO_TYPEA(cmpu, false, gen_helper_cmpu) 332*a2b0b90eSRichard Henderson 333*a2b0b90eSRichard Henderson /* No input carry, but output carry. */ 334*a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 335*a2b0b90eSRichard Henderson { 336*a2b0b90eSRichard Henderson tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina); 337*a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 338*a2b0b90eSRichard Henderson } 339*a2b0b90eSRichard Henderson 340*a2b0b90eSRichard Henderson /* Input and output carry. */ 341*a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 342*a2b0b90eSRichard Henderson { 343*a2b0b90eSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 344*a2b0b90eSRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 345*a2b0b90eSRichard Henderson 346*a2b0b90eSRichard Henderson tcg_gen_not_i32(tmp, ina); 347*a2b0b90eSRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); 348*a2b0b90eSRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 349*a2b0b90eSRichard Henderson 350*a2b0b90eSRichard Henderson tcg_temp_free_i32(zero); 351*a2b0b90eSRichard Henderson tcg_temp_free_i32(tmp); 352*a2b0b90eSRichard Henderson } 353*a2b0b90eSRichard Henderson 354*a2b0b90eSRichard Henderson /* No input or output carry. */ 355*a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 356*a2b0b90eSRichard Henderson { 357*a2b0b90eSRichard Henderson tcg_gen_sub_i32(out, inb, ina); 358*a2b0b90eSRichard Henderson } 359*a2b0b90eSRichard Henderson 360*a2b0b90eSRichard Henderson /* Input carry, no output carry. */ 361*a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 362*a2b0b90eSRichard Henderson { 363*a2b0b90eSRichard Henderson TCGv_i32 nota = tcg_temp_new_i32(); 364*a2b0b90eSRichard Henderson 365*a2b0b90eSRichard Henderson tcg_gen_not_i32(nota, ina); 366*a2b0b90eSRichard Henderson tcg_gen_add_i32(out, inb, nota); 367*a2b0b90eSRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 368*a2b0b90eSRichard Henderson 369*a2b0b90eSRichard Henderson tcg_temp_free_i32(nota); 370*a2b0b90eSRichard Henderson } 371*a2b0b90eSRichard Henderson 372*a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub) 373*a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc) 374*a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk) 375*a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc) 376*a2b0b90eSRichard Henderson 377*a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub) 378*a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc) 379*a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk) 380*a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc) 381*a2b0b90eSRichard Henderson 38220800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 38320800179SRichard Henderson { 38420800179SRichard Henderson /* If opcode_0_illegal, trap. */ 38520800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 38620800179SRichard Henderson trap_illegal(dc, true); 38720800179SRichard Henderson return true; 38820800179SRichard Henderson } 38920800179SRichard Henderson /* 39020800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 39120800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 39220800179SRichard Henderson */ 39320800179SRichard Henderson return false; 39440cbf5b7SEdgar E. Iglesias } 3954acb54baSEdgar E. Iglesias 3964acb54baSEdgar E. Iglesias static void dec_pattern(DisasContext *dc) 3974acb54baSEdgar E. Iglesias { 3984acb54baSEdgar E. Iglesias unsigned int mode; 3994acb54baSEdgar E. Iglesias 4009ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { 4019ba8cd45SEdgar E. Iglesias return; 4021567a005SEdgar E. Iglesias } 4031567a005SEdgar E. Iglesias 4044acb54baSEdgar E. Iglesias mode = dc->opcode & 3; 4054acb54baSEdgar E. Iglesias switch (mode) { 4064acb54baSEdgar E. Iglesias case 0: 4074acb54baSEdgar E. Iglesias /* pcmpbf. */ 4084acb54baSEdgar E. Iglesias if (dc->rd) 4094acb54baSEdgar E. Iglesias gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 4104acb54baSEdgar E. Iglesias break; 4114acb54baSEdgar E. Iglesias case 2: 4124acb54baSEdgar E. Iglesias if (dc->rd) { 413cfeea807SEdgar E. Iglesias tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd], 41486112805SRichard Henderson cpu_R[dc->ra], cpu_R[dc->rb]); 4154acb54baSEdgar E. Iglesias } 4164acb54baSEdgar E. Iglesias break; 4174acb54baSEdgar E. Iglesias case 3: 4184acb54baSEdgar E. Iglesias if (dc->rd) { 419cfeea807SEdgar E. Iglesias tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd], 42086112805SRichard Henderson cpu_R[dc->ra], cpu_R[dc->rb]); 4214acb54baSEdgar E. Iglesias } 4224acb54baSEdgar E. Iglesias break; 4234acb54baSEdgar E. Iglesias default: 4240063ebd6SAndreas Färber cpu_abort(CPU(dc->cpu), 4254acb54baSEdgar E. Iglesias "unsupported pattern insn opcode=%x\n", dc->opcode); 4264acb54baSEdgar E. Iglesias break; 4274acb54baSEdgar E. Iglesias } 4284acb54baSEdgar E. Iglesias } 4294acb54baSEdgar E. Iglesias 4304acb54baSEdgar E. Iglesias static void dec_and(DisasContext *dc) 4314acb54baSEdgar E. Iglesias { 4324acb54baSEdgar E. Iglesias unsigned int not; 4334acb54baSEdgar E. Iglesias 4344acb54baSEdgar E. Iglesias if (!dc->type_b && (dc->imm & (1 << 10))) { 4354acb54baSEdgar E. Iglesias dec_pattern(dc); 4364acb54baSEdgar E. Iglesias return; 4374acb54baSEdgar E. Iglesias } 4384acb54baSEdgar E. Iglesias 4394acb54baSEdgar E. Iglesias not = dc->opcode & (1 << 1); 4404acb54baSEdgar E. Iglesias 4414acb54baSEdgar E. Iglesias if (!dc->rd) 4424acb54baSEdgar E. Iglesias return; 4434acb54baSEdgar E. Iglesias 4444acb54baSEdgar E. Iglesias if (not) { 445cfeea807SEdgar E. Iglesias tcg_gen_andc_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 4464acb54baSEdgar E. Iglesias } else 447cfeea807SEdgar E. Iglesias tcg_gen_and_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 4484acb54baSEdgar E. Iglesias } 4494acb54baSEdgar E. Iglesias 4504acb54baSEdgar E. Iglesias static void dec_or(DisasContext *dc) 4514acb54baSEdgar E. Iglesias { 4524acb54baSEdgar E. Iglesias if (!dc->type_b && (dc->imm & (1 << 10))) { 4534acb54baSEdgar E. Iglesias dec_pattern(dc); 4544acb54baSEdgar E. Iglesias return; 4554acb54baSEdgar E. Iglesias } 4564acb54baSEdgar E. Iglesias 4574acb54baSEdgar E. Iglesias if (dc->rd) 458cfeea807SEdgar E. Iglesias tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 4594acb54baSEdgar E. Iglesias } 4604acb54baSEdgar E. Iglesias 4614acb54baSEdgar E. Iglesias static void dec_xor(DisasContext *dc) 4624acb54baSEdgar E. Iglesias { 4634acb54baSEdgar E. Iglesias if (!dc->type_b && (dc->imm & (1 << 10))) { 4644acb54baSEdgar E. Iglesias dec_pattern(dc); 4654acb54baSEdgar E. Iglesias return; 4664acb54baSEdgar E. Iglesias } 4674acb54baSEdgar E. Iglesias 4684acb54baSEdgar E. Iglesias if (dc->rd) 469cfeea807SEdgar E. Iglesias tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 4704acb54baSEdgar E. Iglesias } 4714acb54baSEdgar E. Iglesias 4721074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 4734acb54baSEdgar E. Iglesias { 4741074c0fbSRichard Henderson TCGv_i32 t; 4751074c0fbSRichard Henderson 4761074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 4771074c0fbSRichard Henderson t = tcg_temp_new_i32(); 4781074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 4791074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 4801074c0fbSRichard Henderson tcg_temp_free_i32(t); 4814acb54baSEdgar E. Iglesias } 4824acb54baSEdgar E. Iglesias 4831074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 4844acb54baSEdgar E. Iglesias { 4854acb54baSEdgar E. Iglesias dc->cpustate_changed = 1; 4861074c0fbSRichard Henderson 4871074c0fbSRichard Henderson /* Install MSR_C. */ 4881074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 4891074c0fbSRichard Henderson 4901074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 4911074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 4924acb54baSEdgar E. Iglesias } 4934acb54baSEdgar E. Iglesias 4944acb54baSEdgar E. Iglesias static void dec_msr(DisasContext *dc) 4954acb54baSEdgar E. Iglesias { 4960063ebd6SAndreas Färber CPUState *cs = CPU(dc->cpu); 497cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 4982023e9a3SEdgar E. Iglesias unsigned int sr, rn; 499f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 5004acb54baSEdgar E. Iglesias 5012023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 5022023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 5032023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 5044acb54baSEdgar E. Iglesias dc->type_b = 1; 5052023e9a3SEdgar E. Iglesias if (to) { 5064acb54baSEdgar E. Iglesias dc->cpustate_changed = 1; 507f0f7e7f7SEdgar E. Iglesias } 508f0f7e7f7SEdgar E. Iglesias 509f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 510f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 511f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 512f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 513f0f7e7f7SEdgar E. Iglesias 514f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 5152023e9a3SEdgar E. Iglesias } 5164acb54baSEdgar E. Iglesias 5174acb54baSEdgar E. Iglesias /* msrclr and msrset. */ 5182023e9a3SEdgar E. Iglesias if (clrset) { 5192023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 5204acb54baSEdgar E. Iglesias 52156837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 5221567a005SEdgar E. Iglesias /* nop??? */ 5231567a005SEdgar E. Iglesias return; 5241567a005SEdgar E. Iglesias } 5251567a005SEdgar E. Iglesias 526bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 5271567a005SEdgar E. Iglesias return; 5281567a005SEdgar E. Iglesias } 5291567a005SEdgar E. Iglesias 5304acb54baSEdgar E. Iglesias if (dc->rd) 5314acb54baSEdgar E. Iglesias msr_read(dc, cpu_R[dc->rd]); 5324acb54baSEdgar E. Iglesias 533cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 534cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 5354acb54baSEdgar E. Iglesias msr_read(dc, t0); 536cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 5374acb54baSEdgar E. Iglesias 5384acb54baSEdgar E. Iglesias if (clr) { 539cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 540cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 5414acb54baSEdgar E. Iglesias } else 542cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 5434acb54baSEdgar E. Iglesias msr_write(dc, t0); 544cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 545cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 546d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 547d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 5484acb54baSEdgar E. Iglesias return; 5494acb54baSEdgar E. Iglesias } 5504acb54baSEdgar E. Iglesias 551bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 5521567a005SEdgar E. Iglesias return; 5531567a005SEdgar E. Iglesias } 5541567a005SEdgar E. Iglesias 5554acb54baSEdgar E. Iglesias #if !defined(CONFIG_USER_ONLY) 5564acb54baSEdgar E. Iglesias /* Catch read/writes to the mmu block. */ 5574acb54baSEdgar E. Iglesias if ((sr & ~0xff) == 0x1000) { 558f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 55905a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 56005a9a651SEdgar E. Iglesias 5614acb54baSEdgar E. Iglesias sr &= 7; 56205a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 56305a9a651SEdgar E. Iglesias if (to) { 564f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 56505a9a651SEdgar E. Iglesias } else { 566f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 56705a9a651SEdgar E. Iglesias } 56805a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 569f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 5704acb54baSEdgar E. Iglesias return; 5714acb54baSEdgar E. Iglesias } 5724acb54baSEdgar E. Iglesias #endif 5734acb54baSEdgar E. Iglesias 5744acb54baSEdgar E. Iglesias if (to) { 5754acb54baSEdgar E. Iglesias switch (sr) { 576aa28e6d4SRichard Henderson case SR_PC: 5774acb54baSEdgar E. Iglesias break; 578aa28e6d4SRichard Henderson case SR_MSR: 5794acb54baSEdgar E. Iglesias msr_write(dc, cpu_R[dc->ra]); 5804acb54baSEdgar E. Iglesias break; 581351527b7SEdgar E. Iglesias case SR_EAR: 582dbdb77c4SRichard Henderson { 583dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 584dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 585dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 586dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 587dbdb77c4SRichard Henderson } 588aa28e6d4SRichard Henderson break; 589351527b7SEdgar E. Iglesias case SR_ESR: 59041ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 59141ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 592aa28e6d4SRichard Henderson break; 593ab6dd380SEdgar E. Iglesias case SR_FSR: 59486017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 59586017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 596aa28e6d4SRichard Henderson break; 597aa28e6d4SRichard Henderson case SR_BTR: 598ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 599ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 600aa28e6d4SRichard Henderson break; 601aa28e6d4SRichard Henderson case SR_EDR: 60239db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 60339db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 6044acb54baSEdgar E. Iglesias break; 6055818dee5SEdgar E. Iglesias case 0x800: 606cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 607cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 6085818dee5SEdgar E. Iglesias break; 6095818dee5SEdgar E. Iglesias case 0x802: 610cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 611cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 6125818dee5SEdgar E. Iglesias break; 6134acb54baSEdgar E. Iglesias default: 6140063ebd6SAndreas Färber cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 6154acb54baSEdgar E. Iglesias break; 6164acb54baSEdgar E. Iglesias } 6174acb54baSEdgar E. Iglesias } else { 6184acb54baSEdgar E. Iglesias switch (sr) { 619aa28e6d4SRichard Henderson case SR_PC: 620d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 6214acb54baSEdgar E. Iglesias break; 622aa28e6d4SRichard Henderson case SR_MSR: 6234acb54baSEdgar E. Iglesias msr_read(dc, cpu_R[dc->rd]); 6244acb54baSEdgar E. Iglesias break; 625351527b7SEdgar E. Iglesias case SR_EAR: 626dbdb77c4SRichard Henderson { 627dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 628dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 629a1b48e3aSEdgar E. Iglesias if (extended) { 630dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 631aa28e6d4SRichard Henderson } else { 632dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 633dbdb77c4SRichard Henderson } 634dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 635a1b48e3aSEdgar E. Iglesias } 636aa28e6d4SRichard Henderson break; 637351527b7SEdgar E. Iglesias case SR_ESR: 63841ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 63941ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 640aa28e6d4SRichard Henderson break; 641351527b7SEdgar E. Iglesias case SR_FSR: 64286017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 64386017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 644aa28e6d4SRichard Henderson break; 645351527b7SEdgar E. Iglesias case SR_BTR: 646ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 647ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 648aa28e6d4SRichard Henderson break; 6497cdae31dSTong Ho case SR_EDR: 65039db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 65139db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 6524acb54baSEdgar E. Iglesias break; 6535818dee5SEdgar E. Iglesias case 0x800: 654cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 655cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 6565818dee5SEdgar E. Iglesias break; 6575818dee5SEdgar E. Iglesias case 0x802: 658cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 659cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 6605818dee5SEdgar E. Iglesias break; 661351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 6624acb54baSEdgar E. Iglesias rn = sr & 0xf; 663cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 66468cee38aSAndreas Färber cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 6654acb54baSEdgar E. Iglesias break; 6664acb54baSEdgar E. Iglesias default: 667a47dddd7SAndreas Färber cpu_abort(cs, "unknown mfs reg %x\n", sr); 6684acb54baSEdgar E. Iglesias break; 6694acb54baSEdgar E. Iglesias } 6704acb54baSEdgar E. Iglesias } 671ee7dbcf8SEdgar E. Iglesias 672ee7dbcf8SEdgar E. Iglesias if (dc->rd == 0) { 673cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 674ee7dbcf8SEdgar E. Iglesias } 6754acb54baSEdgar E. Iglesias } 6764acb54baSEdgar E. Iglesias 6774acb54baSEdgar E. Iglesias /* Multiplier unit. */ 6784acb54baSEdgar E. Iglesias static void dec_mul(DisasContext *dc) 6794acb54baSEdgar E. Iglesias { 680cfeea807SEdgar E. Iglesias TCGv_i32 tmp; 6814acb54baSEdgar E. Iglesias unsigned int subcode; 6824acb54baSEdgar E. Iglesias 6839ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_hw_mul)) { 6841567a005SEdgar E. Iglesias return; 6851567a005SEdgar E. Iglesias } 6861567a005SEdgar E. Iglesias 6874acb54baSEdgar E. Iglesias subcode = dc->imm & 3; 6884acb54baSEdgar E. Iglesias 6894acb54baSEdgar E. Iglesias if (dc->type_b) { 690cfeea807SEdgar E. Iglesias tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 69116ece88dSRichard Henderson return; 6924acb54baSEdgar E. Iglesias } 6934acb54baSEdgar E. Iglesias 6941567a005SEdgar E. Iglesias /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */ 6959b964318SEdgar E. Iglesias if (subcode >= 1 && subcode <= 3 && dc->cpu->cfg.use_hw_mul < 2) { 6961567a005SEdgar E. Iglesias /* nop??? */ 6971567a005SEdgar E. Iglesias } 6981567a005SEdgar E. Iglesias 699cfeea807SEdgar E. Iglesias tmp = tcg_temp_new_i32(); 7004acb54baSEdgar E. Iglesias switch (subcode) { 7014acb54baSEdgar E. Iglesias case 0: 702cfeea807SEdgar E. Iglesias tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 7034acb54baSEdgar E. Iglesias break; 7044acb54baSEdgar E. Iglesias case 1: 705cfeea807SEdgar E. Iglesias tcg_gen_muls2_i32(tmp, cpu_R[dc->rd], 706cfeea807SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 7074acb54baSEdgar E. Iglesias break; 7084acb54baSEdgar E. Iglesias case 2: 709cfeea807SEdgar E. Iglesias tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd], 710cfeea807SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 7114acb54baSEdgar E. Iglesias break; 7124acb54baSEdgar E. Iglesias case 3: 713cfeea807SEdgar E. Iglesias tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 7144acb54baSEdgar E. Iglesias break; 7154acb54baSEdgar E. Iglesias default: 7160063ebd6SAndreas Färber cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode); 7174acb54baSEdgar E. Iglesias break; 7184acb54baSEdgar E. Iglesias } 719cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tmp); 7204acb54baSEdgar E. Iglesias } 7214acb54baSEdgar E. Iglesias 7224acb54baSEdgar E. Iglesias /* Div unit. */ 7234acb54baSEdgar E. Iglesias static void dec_div(DisasContext *dc) 7244acb54baSEdgar E. Iglesias { 7254acb54baSEdgar E. Iglesias unsigned int u; 7264acb54baSEdgar E. Iglesias 7274acb54baSEdgar E. Iglesias u = dc->imm & 2; 7284acb54baSEdgar E. Iglesias 7299ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_div)) { 7309ba8cd45SEdgar E. Iglesias return; 7311567a005SEdgar E. Iglesias } 7321567a005SEdgar E. Iglesias 7334acb54baSEdgar E. Iglesias if (u) 73464254ebaSBlue Swirl gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), 73564254ebaSBlue Swirl cpu_R[dc->ra]); 7364acb54baSEdgar E. Iglesias else 73764254ebaSBlue Swirl gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), 73864254ebaSBlue Swirl cpu_R[dc->ra]); 7394acb54baSEdgar E. Iglesias if (!dc->rd) 740cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[dc->rd], 0); 7414acb54baSEdgar E. Iglesias } 7424acb54baSEdgar E. Iglesias 7434acb54baSEdgar E. Iglesias static void dec_barrel(DisasContext *dc) 7444acb54baSEdgar E. Iglesias { 745cfeea807SEdgar E. Iglesias TCGv_i32 t0; 746faa48d74SEdgar E. Iglesias unsigned int imm_w, imm_s; 747d09b2585SEdgar E. Iglesias bool s, t, e = false, i = false; 7484acb54baSEdgar E. Iglesias 7499ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) { 7501567a005SEdgar E. Iglesias return; 7511567a005SEdgar E. Iglesias } 7521567a005SEdgar E. Iglesias 753faa48d74SEdgar E. Iglesias if (dc->type_b) { 754faa48d74SEdgar E. Iglesias /* Insert and extract are only available in immediate mode. */ 755d09b2585SEdgar E. Iglesias i = extract32(dc->imm, 15, 1); 756faa48d74SEdgar E. Iglesias e = extract32(dc->imm, 14, 1); 757faa48d74SEdgar E. Iglesias } 758e3e84983SEdgar E. Iglesias s = extract32(dc->imm, 10, 1); 759e3e84983SEdgar E. Iglesias t = extract32(dc->imm, 9, 1); 760faa48d74SEdgar E. Iglesias imm_w = extract32(dc->imm, 6, 5); 761faa48d74SEdgar E. Iglesias imm_s = extract32(dc->imm, 0, 5); 7624acb54baSEdgar E. Iglesias 763faa48d74SEdgar E. Iglesias if (e) { 764faa48d74SEdgar E. Iglesias if (imm_w + imm_s > 32 || imm_w == 0) { 765faa48d74SEdgar E. Iglesias /* These inputs have an undefined behavior. */ 766faa48d74SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 767faa48d74SEdgar E. Iglesias imm_w, imm_s); 768faa48d74SEdgar E. Iglesias } else { 769faa48d74SEdgar E. Iglesias tcg_gen_extract_i32(cpu_R[dc->rd], cpu_R[dc->ra], imm_s, imm_w); 770faa48d74SEdgar E. Iglesias } 771d09b2585SEdgar E. Iglesias } else if (i) { 772d09b2585SEdgar E. Iglesias int width = imm_w - imm_s + 1; 773d09b2585SEdgar E. Iglesias 774d09b2585SEdgar E. Iglesias if (imm_w < imm_s) { 775d09b2585SEdgar E. Iglesias /* These inputs have an undefined behavior. */ 776d09b2585SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 777d09b2585SEdgar E. Iglesias imm_w, imm_s); 778d09b2585SEdgar E. Iglesias } else { 779d09b2585SEdgar E. Iglesias tcg_gen_deposit_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_R[dc->ra], 780d09b2585SEdgar E. Iglesias imm_s, width); 781d09b2585SEdgar E. Iglesias } 782faa48d74SEdgar E. Iglesias } else { 783cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 7844acb54baSEdgar E. Iglesias 785cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc))); 786cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, 31); 7874acb54baSEdgar E. Iglesias 7882acf6d53SEdgar E. Iglesias if (s) { 789cfeea807SEdgar E. Iglesias tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7902acf6d53SEdgar E. Iglesias } else { 7912acf6d53SEdgar E. Iglesias if (t) { 792cfeea807SEdgar E. Iglesias tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7932acf6d53SEdgar E. Iglesias } else { 794cfeea807SEdgar E. Iglesias tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7954acb54baSEdgar E. Iglesias } 7964acb54baSEdgar E. Iglesias } 797cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 7982acf6d53SEdgar E. Iglesias } 799faa48d74SEdgar E. Iglesias } 8004acb54baSEdgar E. Iglesias 8014acb54baSEdgar E. Iglesias static void dec_bit(DisasContext *dc) 8024acb54baSEdgar E. Iglesias { 8030063ebd6SAndreas Färber CPUState *cs = CPU(dc->cpu); 804cfeea807SEdgar E. Iglesias TCGv_i32 t0; 8054acb54baSEdgar E. Iglesias unsigned int op; 8064acb54baSEdgar E. Iglesias 807ace2e4daSPeter A. G. Crosthwaite op = dc->ir & ((1 << 9) - 1); 8084acb54baSEdgar E. Iglesias switch (op) { 8094acb54baSEdgar E. Iglesias case 0x21: 8104acb54baSEdgar E. Iglesias /* src. */ 811cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 8124acb54baSEdgar E. Iglesias 8131074c0fbSRichard Henderson tcg_gen_shli_i32(t0, cpu_msr_c, 31); 8141074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); 8154acb54baSEdgar E. Iglesias if (dc->rd) { 816cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 817cfeea807SEdgar E. Iglesias tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0); 8184acb54baSEdgar E. Iglesias } 819cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 8204acb54baSEdgar E. Iglesias break; 8214acb54baSEdgar E. Iglesias 8224acb54baSEdgar E. Iglesias case 0x1: 8234acb54baSEdgar E. Iglesias case 0x41: 8244acb54baSEdgar E. Iglesias /* srl. */ 8251074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); 8264acb54baSEdgar E. Iglesias if (dc->rd) { 8274acb54baSEdgar E. Iglesias if (op == 0x41) 828cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 8294acb54baSEdgar E. Iglesias else 830cfeea807SEdgar E. Iglesias tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 8314acb54baSEdgar E. Iglesias } 8324acb54baSEdgar E. Iglesias break; 8334acb54baSEdgar E. Iglesias case 0x60: 8344acb54baSEdgar E. Iglesias tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 8354acb54baSEdgar E. Iglesias break; 8364acb54baSEdgar E. Iglesias case 0x61: 8374acb54baSEdgar E. Iglesias tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 8384acb54baSEdgar E. Iglesias break; 8394acb54baSEdgar E. Iglesias case 0x64: 840f062a3c7SEdgar E. Iglesias case 0x66: 841f062a3c7SEdgar E. Iglesias case 0x74: 842f062a3c7SEdgar E. Iglesias case 0x76: 8434acb54baSEdgar E. Iglesias /* wdc. */ 844bdfc1e88SEdgar E. Iglesias trap_userspace(dc, true); 8454acb54baSEdgar E. Iglesias break; 8464acb54baSEdgar E. Iglesias case 0x68: 8474acb54baSEdgar E. Iglesias /* wic. */ 848bdfc1e88SEdgar E. Iglesias trap_userspace(dc, true); 8494acb54baSEdgar E. Iglesias break; 85048b5e96fSEdgar E. Iglesias case 0xe0: 8519ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { 8529ba8cd45SEdgar E. Iglesias return; 85348b5e96fSEdgar E. Iglesias } 8548fc5239eSEdgar E. Iglesias if (dc->cpu->cfg.use_pcmp_instr) { 8555318420cSRichard Henderson tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32); 85648b5e96fSEdgar E. Iglesias } 85748b5e96fSEdgar E. Iglesias break; 858ace2e4daSPeter A. G. Crosthwaite case 0x1e0: 859ace2e4daSPeter A. G. Crosthwaite /* swapb */ 860ace2e4daSPeter A. G. Crosthwaite tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 861ace2e4daSPeter A. G. Crosthwaite break; 862b8c6a5d9SPeter Crosthwaite case 0x1e2: 863ace2e4daSPeter A. G. Crosthwaite /*swaph */ 864ace2e4daSPeter A. G. Crosthwaite tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16); 865ace2e4daSPeter A. G. Crosthwaite break; 8664acb54baSEdgar E. Iglesias default: 867a47dddd7SAndreas Färber cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", 868d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, op, dc->rd, dc->ra, dc->rb); 8694acb54baSEdgar E. Iglesias break; 8704acb54baSEdgar E. Iglesias } 8714acb54baSEdgar E. Iglesias } 8724acb54baSEdgar E. Iglesias 8734acb54baSEdgar E. Iglesias static inline void sync_jmpstate(DisasContext *dc) 8744acb54baSEdgar E. Iglesias { 875844bab60SEdgar E. Iglesias if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 8764acb54baSEdgar E. Iglesias if (dc->jmp == JMP_DIRECT) { 8779b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 878844bab60SEdgar E. Iglesias } 8794acb54baSEdgar E. Iglesias dc->jmp = JMP_INDIRECT; 8800f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 8814acb54baSEdgar E. Iglesias } 8824acb54baSEdgar E. Iglesias } 8834acb54baSEdgar E. Iglesias 8844acb54baSEdgar E. Iglesias static void dec_imm(DisasContext *dc) 8854acb54baSEdgar E. Iglesias { 886d7ecb757SRichard Henderson dc->ext_imm = dc->imm << 16; 887d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 8884acb54baSEdgar E. Iglesias dc->tb_flags |= IMM_FLAG; 8894acb54baSEdgar E. Iglesias dc->clear_imm = 0; 8904acb54baSEdgar E. Iglesias } 8914acb54baSEdgar E. Iglesias 892d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) 8934acb54baSEdgar E. Iglesias { 8940e9033c8SEdgar E. Iglesias /* Should be set to true if r1 is used by loadstores. */ 8950e9033c8SEdgar E. Iglesias bool stackprot = false; 896403322eaSEdgar E. Iglesias TCGv_i32 t32; 8975818dee5SEdgar E. Iglesias 8985818dee5SEdgar E. Iglesias /* All load/stores use ra. */ 8999aaaa181SAlistair Francis if (dc->ra == 1 && dc->cpu->cfg.stackprot) { 9000e9033c8SEdgar E. Iglesias stackprot = true; 9015818dee5SEdgar E. Iglesias } 9024acb54baSEdgar E. Iglesias 9039ef55357SEdgar E. Iglesias /* Treat the common cases first. */ 9044acb54baSEdgar E. Iglesias if (!dc->type_b) { 905d248e1beSEdgar E. Iglesias if (ea) { 906d248e1beSEdgar E. Iglesias int addr_size = dc->cpu->cfg.addr_size; 907d248e1beSEdgar E. Iglesias 908d248e1beSEdgar E. Iglesias if (addr_size == 32) { 909d248e1beSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 910d248e1beSEdgar E. Iglesias return; 911d248e1beSEdgar E. Iglesias } 912d248e1beSEdgar E. Iglesias 913d248e1beSEdgar E. Iglesias tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]); 914d248e1beSEdgar E. Iglesias if (addr_size < 64) { 915d248e1beSEdgar E. Iglesias /* Mask off out of range bits. */ 916d248e1beSEdgar E. Iglesias tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size)); 917d248e1beSEdgar E. Iglesias } 918d248e1beSEdgar E. Iglesias return; 919d248e1beSEdgar E. Iglesias } 920d248e1beSEdgar E. Iglesias 9210dc4af5cSEdgar E. Iglesias /* If any of the regs is r0, set t to the value of the other reg. */ 9224b5ef0b5SEdgar E. Iglesias if (dc->ra == 0) { 923403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 9240dc4af5cSEdgar E. Iglesias return; 9254b5ef0b5SEdgar E. Iglesias } else if (dc->rb == 0) { 926403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]); 9270dc4af5cSEdgar E. Iglesias return; 9284b5ef0b5SEdgar E. Iglesias } 9294b5ef0b5SEdgar E. Iglesias 9309aaaa181SAlistair Francis if (dc->rb == 1 && dc->cpu->cfg.stackprot) { 9310e9033c8SEdgar E. Iglesias stackprot = true; 9325818dee5SEdgar E. Iglesias } 9335818dee5SEdgar E. Iglesias 934403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 935403322eaSEdgar E. Iglesias tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]); 936403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 937403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 9385818dee5SEdgar E. Iglesias 9395818dee5SEdgar E. Iglesias if (stackprot) { 9400a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 9415818dee5SEdgar E. Iglesias } 9420dc4af5cSEdgar E. Iglesias return; 9434acb54baSEdgar E. Iglesias } 9444acb54baSEdgar E. Iglesias /* Immediate. */ 945403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 946d7ecb757SRichard Henderson tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc)); 947403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 948403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 9494acb54baSEdgar E. Iglesias 9505818dee5SEdgar E. Iglesias if (stackprot) { 9510a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 9525818dee5SEdgar E. Iglesias } 9530dc4af5cSEdgar E. Iglesias return; 9544acb54baSEdgar E. Iglesias } 9554acb54baSEdgar E. Iglesias 9564acb54baSEdgar E. Iglesias static void dec_load(DisasContext *dc) 9574acb54baSEdgar E. Iglesias { 958403322eaSEdgar E. Iglesias TCGv_i32 v; 959403322eaSEdgar E. Iglesias TCGv addr; 9608534063aSEdgar E. Iglesias unsigned int size; 961d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 962d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 96314776ab5STony Nguyen MemOp mop; 9644acb54baSEdgar E. Iglesias 96547acdd63SRichard Henderson mop = dc->opcode & 3; 96647acdd63SRichard Henderson size = 1 << mop; 9679f8beb66SEdgar E. Iglesias if (!dc->type_b) { 968d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 9698534063aSEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 9708534063aSEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 9719f8beb66SEdgar E. Iglesias } 97247acdd63SRichard Henderson mop |= MO_TE; 97347acdd63SRichard Henderson if (rev) { 97447acdd63SRichard Henderson mop ^= MO_BSWAP; 97547acdd63SRichard Henderson } 9769f8beb66SEdgar E. Iglesias 9779ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 9780187688fSEdgar E. Iglesias return; 9790187688fSEdgar E. Iglesias } 9804acb54baSEdgar E. Iglesias 981d248e1beSEdgar E. Iglesias if (trap_userspace(dc, ea)) { 982d248e1beSEdgar E. Iglesias return; 983d248e1beSEdgar E. Iglesias } 984d248e1beSEdgar E. Iglesias 9854acb54baSEdgar E. Iglesias t_sync_flags(dc); 986403322eaSEdgar E. Iglesias addr = tcg_temp_new(); 987d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 988d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 989d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 9904acb54baSEdgar E. Iglesias 9919f8beb66SEdgar E. Iglesias /* 9929f8beb66SEdgar E. Iglesias * When doing reverse accesses we need to do two things. 9939f8beb66SEdgar E. Iglesias * 9944ff9786cSStefan Weil * 1. Reverse the address wrt endianness. 9959f8beb66SEdgar E. Iglesias * 2. Byteswap the data lanes on the way back into the CPU core. 9969f8beb66SEdgar E. Iglesias */ 9979f8beb66SEdgar E. Iglesias if (rev && size != 4) { 9989f8beb66SEdgar E. Iglesias /* Endian reverse the address. t is addr. */ 9999f8beb66SEdgar E. Iglesias switch (size) { 10009f8beb66SEdgar E. Iglesias case 1: 10019f8beb66SEdgar E. Iglesias { 1002a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 10039f8beb66SEdgar E. Iglesias break; 10049f8beb66SEdgar E. Iglesias } 10059f8beb66SEdgar E. Iglesias 10069f8beb66SEdgar E. Iglesias case 2: 10079f8beb66SEdgar E. Iglesias /* 00 -> 10 10089f8beb66SEdgar E. Iglesias 10 -> 00. */ 1009403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 10109f8beb66SEdgar E. Iglesias break; 10119f8beb66SEdgar E. Iglesias default: 10120063ebd6SAndreas Färber cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 10139f8beb66SEdgar E. Iglesias break; 10149f8beb66SEdgar E. Iglesias } 10159f8beb66SEdgar E. Iglesias } 10169f8beb66SEdgar E. Iglesias 10178cc9b43fSPeter A. G. Crosthwaite /* lwx does not throw unaligned access errors, so force alignment */ 10188cc9b43fSPeter A. G. Crosthwaite if (ex) { 1019403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 10208cc9b43fSPeter A. G. Crosthwaite } 10218cc9b43fSPeter A. G. Crosthwaite 10224acb54baSEdgar E. Iglesias /* If we get a fault on a dslot, the jmpstate better be in sync. */ 10234acb54baSEdgar E. Iglesias sync_jmpstate(dc); 1024968a40f6SEdgar E. Iglesias 1025968a40f6SEdgar E. Iglesias /* Verify alignment if needed. */ 1026a12f6507SEdgar E. Iglesias /* 1027a12f6507SEdgar E. Iglesias * Microblaze gives MMU faults priority over faults due to 1028a12f6507SEdgar E. Iglesias * unaligned addresses. That's why we speculatively do the load 1029a12f6507SEdgar E. Iglesias * into v. If the load succeeds, we verify alignment of the 1030a12f6507SEdgar E. Iglesias * address and if that succeeds we write into the destination reg. 1031a12f6507SEdgar E. Iglesias */ 1032cfeea807SEdgar E. Iglesias v = tcg_temp_new_i32(); 1033d248e1beSEdgar E. Iglesias tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); 1034a12f6507SEdgar E. Iglesias 10351507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1036a6338015SEdgar E. Iglesias TCGv_i32 t0 = tcg_const_i32(0); 1037a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1038a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1039a6338015SEdgar E. Iglesias 1040d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1041a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t0, tsize); 1042a6338015SEdgar E. Iglesias 1043a6338015SEdgar E. Iglesias tcg_temp_free_i32(t0); 1044a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1045a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 104647acdd63SRichard Henderson } 104747acdd63SRichard Henderson 104847acdd63SRichard Henderson if (ex) { 10499b158558SRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 10509b158558SRichard Henderson tcg_gen_mov_i32(cpu_res_val, v); 105147acdd63SRichard Henderson } 10529f8beb66SEdgar E. Iglesias if (dc->rd) { 1053cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(cpu_R[dc->rd], v); 10549f8beb66SEdgar E. Iglesias } 1055cfeea807SEdgar E. Iglesias tcg_temp_free_i32(v); 10564acb54baSEdgar E. Iglesias 10578cc9b43fSPeter A. G. Crosthwaite if (ex) { /* lwx */ 1058b6af0975SDaniel P. Berrange /* no support for AXI exclusive so always clear C */ 10591074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 10608cc9b43fSPeter A. G. Crosthwaite } 10618cc9b43fSPeter A. G. Crosthwaite 1062403322eaSEdgar E. Iglesias tcg_temp_free(addr); 10634acb54baSEdgar E. Iglesias } 10644acb54baSEdgar E. Iglesias 10654acb54baSEdgar E. Iglesias static void dec_store(DisasContext *dc) 10664acb54baSEdgar E. Iglesias { 1067403322eaSEdgar E. Iglesias TCGv addr; 106842a268c2SRichard Henderson TCGLabel *swx_skip = NULL; 1069b51b3d43SEdgar E. Iglesias unsigned int size; 1070d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 1071d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 107214776ab5STony Nguyen MemOp mop; 10734acb54baSEdgar E. Iglesias 107447acdd63SRichard Henderson mop = dc->opcode & 3; 107547acdd63SRichard Henderson size = 1 << mop; 10769f8beb66SEdgar E. Iglesias if (!dc->type_b) { 1077d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 1078b51b3d43SEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 1079b51b3d43SEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 10809f8beb66SEdgar E. Iglesias } 108147acdd63SRichard Henderson mop |= MO_TE; 108247acdd63SRichard Henderson if (rev) { 108347acdd63SRichard Henderson mop ^= MO_BSWAP; 108447acdd63SRichard Henderson } 10854acb54baSEdgar E. Iglesias 10869ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 10870187688fSEdgar E. Iglesias return; 10880187688fSEdgar E. Iglesias } 10890187688fSEdgar E. Iglesias 1090d248e1beSEdgar E. Iglesias trap_userspace(dc, ea); 1091d248e1beSEdgar E. Iglesias 10924acb54baSEdgar E. Iglesias t_sync_flags(dc); 10934acb54baSEdgar E. Iglesias /* If we get a fault on a dslot, the jmpstate better be in sync. */ 10944acb54baSEdgar E. Iglesias sync_jmpstate(dc); 10950dc4af5cSEdgar E. Iglesias /* SWX needs a temp_local. */ 1096403322eaSEdgar E. Iglesias addr = ex ? tcg_temp_local_new() : tcg_temp_new(); 1097d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 1098d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 1099d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 1100968a40f6SEdgar E. Iglesias 1101083dbf48SPeter A. G. Crosthwaite if (ex) { /* swx */ 1102cfeea807SEdgar E. Iglesias TCGv_i32 tval; 11038cc9b43fSPeter A. G. Crosthwaite 11048cc9b43fSPeter A. G. Crosthwaite /* swx does not throw unaligned access errors, so force alignment */ 1105403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 11068cc9b43fSPeter A. G. Crosthwaite 11071074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 11088cc9b43fSPeter A. G. Crosthwaite swx_skip = gen_new_label(); 11099b158558SRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); 111011a76217SEdgar E. Iglesias 1111071cdc67SEdgar E. Iglesias /* 1112071cdc67SEdgar E. Iglesias * Compare the value loaded at lwx with current contents of 1113071cdc67SEdgar E. Iglesias * the reserved location. 1114071cdc67SEdgar E. Iglesias */ 1115cfeea807SEdgar E. Iglesias tval = tcg_temp_new_i32(); 1116071cdc67SEdgar E. Iglesias 11179b158558SRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val, 1118071cdc67SEdgar E. Iglesias cpu_R[dc->rd], mem_index, 1119071cdc67SEdgar E. Iglesias mop); 1120071cdc67SEdgar E. Iglesias 11219b158558SRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); 11221074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1123cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tval); 11248cc9b43fSPeter A. G. Crosthwaite } 11258cc9b43fSPeter A. G. Crosthwaite 11269f8beb66SEdgar E. Iglesias if (rev && size != 4) { 11279f8beb66SEdgar E. Iglesias /* Endian reverse the address. t is addr. */ 11289f8beb66SEdgar E. Iglesias switch (size) { 11299f8beb66SEdgar E. Iglesias case 1: 11309f8beb66SEdgar E. Iglesias { 1131a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 11329f8beb66SEdgar E. Iglesias break; 11339f8beb66SEdgar E. Iglesias } 11349f8beb66SEdgar E. Iglesias 11359f8beb66SEdgar E. Iglesias case 2: 11369f8beb66SEdgar E. Iglesias /* 00 -> 10 11379f8beb66SEdgar E. Iglesias 10 -> 00. */ 11389f8beb66SEdgar E. Iglesias /* Force addr into the temp. */ 1139403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 11409f8beb66SEdgar E. Iglesias break; 11419f8beb66SEdgar E. Iglesias default: 11420063ebd6SAndreas Färber cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 11439f8beb66SEdgar E. Iglesias break; 11449f8beb66SEdgar E. Iglesias } 11459f8beb66SEdgar E. Iglesias } 1146071cdc67SEdgar E. Iglesias 1147071cdc67SEdgar E. Iglesias if (!ex) { 1148d248e1beSEdgar E. Iglesias tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); 1149071cdc67SEdgar E. Iglesias } 1150a12f6507SEdgar E. Iglesias 1151968a40f6SEdgar E. Iglesias /* Verify alignment if needed. */ 11521507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1153a6338015SEdgar E. Iglesias TCGv_i32 t1 = tcg_const_i32(1); 1154a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1155a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1156a6338015SEdgar E. Iglesias 1157d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1158a12f6507SEdgar E. Iglesias /* FIXME: if the alignment is wrong, we should restore the value 11594abf79a4SDong Xu Wang * in memory. One possible way to achieve this is to probe 11609f8beb66SEdgar E. Iglesias * the MMU prior to the memaccess, thay way we could put 11619f8beb66SEdgar E. Iglesias * the alignment checks in between the probe and the mem 11629f8beb66SEdgar E. Iglesias * access. 1163a12f6507SEdgar E. Iglesias */ 1164a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t1, tsize); 1165a6338015SEdgar E. Iglesias 1166a6338015SEdgar E. Iglesias tcg_temp_free_i32(t1); 1167a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1168a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1169968a40f6SEdgar E. Iglesias } 1170083dbf48SPeter A. G. Crosthwaite 11718cc9b43fSPeter A. G. Crosthwaite if (ex) { 11728cc9b43fSPeter A. G. Crosthwaite gen_set_label(swx_skip); 1173083dbf48SPeter A. G. Crosthwaite } 1174968a40f6SEdgar E. Iglesias 1175403322eaSEdgar E. Iglesias tcg_temp_free(addr); 11764acb54baSEdgar E. Iglesias } 11774acb54baSEdgar E. Iglesias 11784acb54baSEdgar E. Iglesias static inline void eval_cc(DisasContext *dc, unsigned int cc, 11799e6e1828SEdgar E. Iglesias TCGv_i32 d, TCGv_i32 a) 11804acb54baSEdgar E. Iglesias { 1181d89b86e9SEdgar E. Iglesias static const int mb_to_tcg_cc[] = { 1182d89b86e9SEdgar E. Iglesias [CC_EQ] = TCG_COND_EQ, 1183d89b86e9SEdgar E. Iglesias [CC_NE] = TCG_COND_NE, 1184d89b86e9SEdgar E. Iglesias [CC_LT] = TCG_COND_LT, 1185d89b86e9SEdgar E. Iglesias [CC_LE] = TCG_COND_LE, 1186d89b86e9SEdgar E. Iglesias [CC_GE] = TCG_COND_GE, 1187d89b86e9SEdgar E. Iglesias [CC_GT] = TCG_COND_GT, 1188d89b86e9SEdgar E. Iglesias }; 1189d89b86e9SEdgar E. Iglesias 11904acb54baSEdgar E. Iglesias switch (cc) { 11914acb54baSEdgar E. Iglesias case CC_EQ: 11924acb54baSEdgar E. Iglesias case CC_NE: 11934acb54baSEdgar E. Iglesias case CC_LT: 11944acb54baSEdgar E. Iglesias case CC_LE: 11954acb54baSEdgar E. Iglesias case CC_GE: 11964acb54baSEdgar E. Iglesias case CC_GT: 11979e6e1828SEdgar E. Iglesias tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); 11984acb54baSEdgar E. Iglesias break; 11994acb54baSEdgar E. Iglesias default: 12000063ebd6SAndreas Färber cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); 12014acb54baSEdgar E. Iglesias break; 12024acb54baSEdgar E. Iglesias } 12034acb54baSEdgar E. Iglesias } 12044acb54baSEdgar E. Iglesias 12050f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) 12064acb54baSEdgar E. Iglesias { 12070f96e96bSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 1208e956caf2SEdgar E. Iglesias 12090f96e96bSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, 12109b158558SRichard Henderson cpu_btaken, zero, 1211e956caf2SEdgar E. Iglesias pc_true, pc_false); 1212e956caf2SEdgar E. Iglesias 12130f96e96bSRichard Henderson tcg_temp_free_i32(zero); 12144acb54baSEdgar E. Iglesias } 12154acb54baSEdgar E. Iglesias 1216f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1217f91c60f0SEdgar E. Iglesias { 1218f91c60f0SEdgar E. Iglesias TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)); 1219f91c60f0SEdgar E. Iglesias 1220f91c60f0SEdgar E. Iglesias dc->delayed_branch = 2; 1221f91c60f0SEdgar E. Iglesias dc->tb_flags |= D_FLAG; 1222f91c60f0SEdgar E. Iglesias 1223f91c60f0SEdgar E. Iglesias tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm)); 1224f91c60f0SEdgar E. Iglesias tcg_temp_free_i32(tmp); 1225f91c60f0SEdgar E. Iglesias } 1226f91c60f0SEdgar E. Iglesias 12274acb54baSEdgar E. Iglesias static void dec_bcc(DisasContext *dc) 12284acb54baSEdgar E. Iglesias { 12294acb54baSEdgar E. Iglesias unsigned int cc; 12304acb54baSEdgar E. Iglesias unsigned int dslot; 12314acb54baSEdgar E. Iglesias 12324acb54baSEdgar E. Iglesias cc = EXTRACT_FIELD(dc->ir, 21, 23); 12334acb54baSEdgar E. Iglesias dslot = dc->ir & (1 << 25); 12344acb54baSEdgar E. Iglesias 12354acb54baSEdgar E. Iglesias dc->delayed_branch = 1; 12364acb54baSEdgar E. Iglesias if (dslot) { 1237f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 12384acb54baSEdgar E. Iglesias } 12394acb54baSEdgar E. Iglesias 1240d7ecb757SRichard Henderson if (dc->type_b) { 1241844bab60SEdgar E. Iglesias dc->jmp = JMP_DIRECT_CC; 1242d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1243d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 124461204ce8SEdgar E. Iglesias } else { 124523979dc5SEdgar E. Iglesias dc->jmp = JMP_INDIRECT; 1246d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 124761204ce8SEdgar E. Iglesias } 12489b158558SRichard Henderson eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); 12494acb54baSEdgar E. Iglesias } 12504acb54baSEdgar E. Iglesias 12514acb54baSEdgar E. Iglesias static void dec_br(DisasContext *dc) 12524acb54baSEdgar E. Iglesias { 12539f6113c7SEdgar E. Iglesias unsigned int dslot, link, abs, mbar; 12544acb54baSEdgar E. Iglesias 12554acb54baSEdgar E. Iglesias dslot = dc->ir & (1 << 20); 12564acb54baSEdgar E. Iglesias abs = dc->ir & (1 << 19); 12574acb54baSEdgar E. Iglesias link = dc->ir & (1 << 18); 12589f6113c7SEdgar E. Iglesias 12599f6113c7SEdgar E. Iglesias /* Memory barrier. */ 12609f6113c7SEdgar E. Iglesias mbar = (dc->ir >> 16) & 31; 12619f6113c7SEdgar E. Iglesias if (mbar == 2 && dc->imm == 4) { 1262badcbf9dSEdgar E. Iglesias uint16_t mbar_imm = dc->rd; 1263badcbf9dSEdgar E. Iglesias 12643f172744SEdgar E. Iglesias /* Data access memory barrier. */ 12653f172744SEdgar E. Iglesias if ((mbar_imm & 2) == 0) { 12663f172744SEdgar E. Iglesias tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 12673f172744SEdgar E. Iglesias } 12683f172744SEdgar E. Iglesias 12695d45de97SEdgar E. Iglesias /* mbar IMM & 16 decodes to sleep. */ 1270badcbf9dSEdgar E. Iglesias if (mbar_imm & 16) { 127141ba37c4SRichard Henderson TCGv_i32 tmp_1; 12725d45de97SEdgar E. Iglesias 1273b4919e7dSEdgar E. Iglesias if (trap_userspace(dc, true)) { 1274b4919e7dSEdgar E. Iglesias /* Sleep is a privileged instruction. */ 1275b4919e7dSEdgar E. Iglesias return; 1276b4919e7dSEdgar E. Iglesias } 1277b4919e7dSEdgar E. Iglesias 12785d45de97SEdgar E. Iglesias t_sync_flags(dc); 127941ba37c4SRichard Henderson 128041ba37c4SRichard Henderson tmp_1 = tcg_const_i32(1); 12815d45de97SEdgar E. Iglesias tcg_gen_st_i32(tmp_1, cpu_env, 12825d45de97SEdgar E. Iglesias -offsetof(MicroBlazeCPU, env) 12835d45de97SEdgar E. Iglesias +offsetof(CPUState, halted)); 12845d45de97SEdgar E. Iglesias tcg_temp_free_i32(tmp_1); 128541ba37c4SRichard Henderson 1286d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 128741ba37c4SRichard Henderson 128841ba37c4SRichard Henderson gen_raise_exception(dc, EXCP_HLT); 12895d45de97SEdgar E. Iglesias return; 12905d45de97SEdgar E. Iglesias } 12919f6113c7SEdgar E. Iglesias /* Break the TB. */ 12929f6113c7SEdgar E. Iglesias dc->cpustate_changed = 1; 12939f6113c7SEdgar E. Iglesias return; 12949f6113c7SEdgar E. Iglesias } 12959f6113c7SEdgar E. Iglesias 1296d7ecb757SRichard Henderson if (abs && link && !dslot) { 1297d7ecb757SRichard Henderson if (dc->type_b) { 1298d7ecb757SRichard Henderson /* BRKI */ 1299d7ecb757SRichard Henderson uint32_t imm = dec_alu_typeb_imm(dc); 1300d7ecb757SRichard Henderson if (trap_userspace(dc, imm != 8 && imm != 0x18)) { 1301d7ecb757SRichard Henderson return; 1302d7ecb757SRichard Henderson } 1303d7ecb757SRichard Henderson } else { 1304d7ecb757SRichard Henderson /* BRK */ 1305d7ecb757SRichard Henderson if (trap_userspace(dc, true)) { 1306d7ecb757SRichard Henderson return; 1307d7ecb757SRichard Henderson } 1308d7ecb757SRichard Henderson } 1309d7ecb757SRichard Henderson } 1310d7ecb757SRichard Henderson 13114acb54baSEdgar E. Iglesias dc->delayed_branch = 1; 13124acb54baSEdgar E. Iglesias if (dslot) { 1313f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 13144acb54baSEdgar E. Iglesias } 1315d7ecb757SRichard Henderson if (link && dc->rd) { 1316d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1317d7ecb757SRichard Henderson } 13184acb54baSEdgar E. Iglesias 13194acb54baSEdgar E. Iglesias if (abs) { 1320d7ecb757SRichard Henderson if (dc->type_b) { 1321d7ecb757SRichard Henderson uint32_t dest = dec_alu_typeb_imm(dc); 1322d7ecb757SRichard Henderson 1323d7ecb757SRichard Henderson dc->jmp = JMP_DIRECT; 1324d7ecb757SRichard Henderson dc->jmp_pc = dest; 1325d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dest); 1326ff21f70aSEdgar E. Iglesias if (link && !dslot) { 1327d7ecb757SRichard Henderson switch (dest) { 1328d7ecb757SRichard Henderson case 8: 1329d7ecb757SRichard Henderson case 0x18: 1330d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 1331d7ecb757SRichard Henderson break; 1332d7ecb757SRichard Henderson case 0: 1333d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1334d7ecb757SRichard Henderson break; 1335d7ecb757SRichard Henderson } 1336d7ecb757SRichard Henderson } 1337d7ecb757SRichard Henderson } else { 1338d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1339d7ecb757SRichard Henderson tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]); 1340d7ecb757SRichard Henderson if (link && !dslot) { 134141ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 134241ba37c4SRichard Henderson } 1343ff21f70aSEdgar E. Iglesias } 1344d7ecb757SRichard Henderson } else if (dc->type_b) { 134561204ce8SEdgar E. Iglesias dc->jmp = JMP_DIRECT; 1346d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1347d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 134861204ce8SEdgar E. Iglesias } else { 1349d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1350d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1351d7ecb757SRichard Henderson } 13529b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 13534acb54baSEdgar E. Iglesias } 13544acb54baSEdgar E. Iglesias 13554acb54baSEdgar E. Iglesias static inline void do_rti(DisasContext *dc) 13564acb54baSEdgar E. Iglesias { 1357cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1358cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1359cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13603e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13610a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 13620a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1363cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 13644acb54baSEdgar E. Iglesias 1365cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1366cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 13674acb54baSEdgar E. Iglesias msr_write(dc, t1); 1368cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1369cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 13704acb54baSEdgar E. Iglesias dc->tb_flags &= ~DRTI_FLAG; 13714acb54baSEdgar E. Iglesias } 13724acb54baSEdgar E. Iglesias 13734acb54baSEdgar E. Iglesias static inline void do_rtb(DisasContext *dc) 13744acb54baSEdgar E. Iglesias { 1375cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1376cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1377cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13783e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13790a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1380cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1381cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 13824acb54baSEdgar E. Iglesias 1383cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1384cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 13854acb54baSEdgar E. Iglesias msr_write(dc, t1); 1386cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1387cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 13884acb54baSEdgar E. Iglesias dc->tb_flags &= ~DRTB_FLAG; 13894acb54baSEdgar E. Iglesias } 13904acb54baSEdgar E. Iglesias 13914acb54baSEdgar E. Iglesias static inline void do_rte(DisasContext *dc) 13924acb54baSEdgar E. Iglesias { 1393cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1394cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1395cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13964acb54baSEdgar E. Iglesias 13973e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13980a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1399cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1400cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1401cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 14024acb54baSEdgar E. Iglesias 1403cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1404cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 14054acb54baSEdgar E. Iglesias msr_write(dc, t1); 1406cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1407cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 14084acb54baSEdgar E. Iglesias dc->tb_flags &= ~DRTE_FLAG; 14094acb54baSEdgar E. Iglesias } 14104acb54baSEdgar E. Iglesias 14114acb54baSEdgar E. Iglesias static void dec_rts(DisasContext *dc) 14124acb54baSEdgar E. Iglesias { 14134acb54baSEdgar E. Iglesias unsigned int b_bit, i_bit, e_bit; 14144acb54baSEdgar E. Iglesias 14154acb54baSEdgar E. Iglesias i_bit = dc->ir & (1 << 21); 14164acb54baSEdgar E. Iglesias b_bit = dc->ir & (1 << 22); 14174acb54baSEdgar E. Iglesias e_bit = dc->ir & (1 << 23); 14184acb54baSEdgar E. Iglesias 1419bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1420bdfc1e88SEdgar E. Iglesias return; 1421bdfc1e88SEdgar E. Iglesias } 1422bdfc1e88SEdgar E. Iglesias 1423f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 14244acb54baSEdgar E. Iglesias 14254acb54baSEdgar E. Iglesias if (i_bit) { 14264acb54baSEdgar E. Iglesias dc->tb_flags |= DRTI_FLAG; 14274acb54baSEdgar E. Iglesias } else if (b_bit) { 14284acb54baSEdgar E. Iglesias dc->tb_flags |= DRTB_FLAG; 14294acb54baSEdgar E. Iglesias } else if (e_bit) { 14304acb54baSEdgar E. Iglesias dc->tb_flags |= DRTE_FLAG; 143111105d67SRichard Henderson } 14324acb54baSEdgar E. Iglesias 143323979dc5SEdgar E. Iglesias dc->jmp = JMP_INDIRECT; 14349b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 14350f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 14364acb54baSEdgar E. Iglesias } 14374acb54baSEdgar E. Iglesias 143897694c57SEdgar E. Iglesias static int dec_check_fpuv2(DisasContext *dc) 143997694c57SEdgar E. Iglesias { 1440be67e9abSAlistair Francis if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { 144141ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_FPU); 144297694c57SEdgar E. Iglesias } 14432016a6a7SJoe Komlodi return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; 144497694c57SEdgar E. Iglesias } 144597694c57SEdgar E. Iglesias 14461567a005SEdgar E. Iglesias static void dec_fpu(DisasContext *dc) 14471567a005SEdgar E. Iglesias { 144897694c57SEdgar E. Iglesias unsigned int fpu_insn; 144997694c57SEdgar E. Iglesias 14509ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) { 14511567a005SEdgar E. Iglesias return; 14521567a005SEdgar E. Iglesias } 14531567a005SEdgar E. Iglesias 145497694c57SEdgar E. Iglesias fpu_insn = (dc->ir >> 7) & 7; 145597694c57SEdgar E. Iglesias 145697694c57SEdgar E. Iglesias switch (fpu_insn) { 145797694c57SEdgar E. Iglesias case 0: 145864254ebaSBlue Swirl gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 145964254ebaSBlue Swirl cpu_R[dc->rb]); 146097694c57SEdgar E. Iglesias break; 146197694c57SEdgar E. Iglesias 146297694c57SEdgar E. Iglesias case 1: 146364254ebaSBlue Swirl gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 146464254ebaSBlue Swirl cpu_R[dc->rb]); 146597694c57SEdgar E. Iglesias break; 146697694c57SEdgar E. Iglesias 146797694c57SEdgar E. Iglesias case 2: 146864254ebaSBlue Swirl gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 146964254ebaSBlue Swirl cpu_R[dc->rb]); 147097694c57SEdgar E. Iglesias break; 147197694c57SEdgar E. Iglesias 147297694c57SEdgar E. Iglesias case 3: 147364254ebaSBlue Swirl gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 147464254ebaSBlue Swirl cpu_R[dc->rb]); 147597694c57SEdgar E. Iglesias break; 147697694c57SEdgar E. Iglesias 147797694c57SEdgar E. Iglesias case 4: 147897694c57SEdgar E. Iglesias switch ((dc->ir >> 4) & 7) { 147997694c57SEdgar E. Iglesias case 0: 148064254ebaSBlue Swirl gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env, 148197694c57SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 148297694c57SEdgar E. Iglesias break; 148397694c57SEdgar E. Iglesias case 1: 148464254ebaSBlue Swirl gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env, 148597694c57SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 148697694c57SEdgar E. Iglesias break; 148797694c57SEdgar E. Iglesias case 2: 148864254ebaSBlue Swirl gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env, 148997694c57SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 149097694c57SEdgar E. Iglesias break; 149197694c57SEdgar E. Iglesias case 3: 149264254ebaSBlue Swirl gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env, 149397694c57SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 149497694c57SEdgar E. Iglesias break; 149597694c57SEdgar E. Iglesias case 4: 149664254ebaSBlue Swirl gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env, 149797694c57SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 149897694c57SEdgar E. Iglesias break; 149997694c57SEdgar E. Iglesias case 5: 150064254ebaSBlue Swirl gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env, 150197694c57SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 150297694c57SEdgar E. Iglesias break; 150397694c57SEdgar E. Iglesias case 6: 150464254ebaSBlue Swirl gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env, 150597694c57SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 150697694c57SEdgar E. Iglesias break; 150797694c57SEdgar E. Iglesias default: 150871547a3bSBlue Swirl qemu_log_mask(LOG_UNIMP, 150971547a3bSBlue Swirl "unimplemented fcmp fpu_insn=%x pc=%x" 151071547a3bSBlue Swirl " opc=%x\n", 1511d4705ae0SRichard Henderson fpu_insn, (uint32_t)dc->base.pc_next, 1512d4705ae0SRichard Henderson dc->opcode); 15131567a005SEdgar E. Iglesias dc->abort_at_next_insn = 1; 151497694c57SEdgar E. Iglesias break; 151597694c57SEdgar E. Iglesias } 151697694c57SEdgar E. Iglesias break; 151797694c57SEdgar E. Iglesias 151897694c57SEdgar E. Iglesias case 5: 151997694c57SEdgar E. Iglesias if (!dec_check_fpuv2(dc)) { 152097694c57SEdgar E. Iglesias return; 152197694c57SEdgar E. Iglesias } 152264254ebaSBlue Swirl gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 152397694c57SEdgar E. Iglesias break; 152497694c57SEdgar E. Iglesias 152597694c57SEdgar E. Iglesias case 6: 152697694c57SEdgar E. Iglesias if (!dec_check_fpuv2(dc)) { 152797694c57SEdgar E. Iglesias return; 152897694c57SEdgar E. Iglesias } 152964254ebaSBlue Swirl gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 153097694c57SEdgar E. Iglesias break; 153197694c57SEdgar E. Iglesias 153297694c57SEdgar E. Iglesias case 7: 153397694c57SEdgar E. Iglesias if (!dec_check_fpuv2(dc)) { 153497694c57SEdgar E. Iglesias return; 153597694c57SEdgar E. Iglesias } 153664254ebaSBlue Swirl gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 153797694c57SEdgar E. Iglesias break; 153897694c57SEdgar E. Iglesias 153997694c57SEdgar E. Iglesias default: 154071547a3bSBlue Swirl qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x" 154171547a3bSBlue Swirl " opc=%x\n", 1542d4705ae0SRichard Henderson fpu_insn, (uint32_t)dc->base.pc_next, dc->opcode); 154397694c57SEdgar E. Iglesias dc->abort_at_next_insn = 1; 154497694c57SEdgar E. Iglesias break; 154597694c57SEdgar E. Iglesias } 15461567a005SEdgar E. Iglesias } 15471567a005SEdgar E. Iglesias 15484acb54baSEdgar E. Iglesias static void dec_null(DisasContext *dc) 15494acb54baSEdgar E. Iglesias { 15509ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 155102b33596SEdgar E. Iglesias return; 155202b33596SEdgar E. Iglesias } 1553d4705ae0SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", 1554d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, dc->opcode); 15554acb54baSEdgar E. Iglesias dc->abort_at_next_insn = 1; 15564acb54baSEdgar E. Iglesias } 15574acb54baSEdgar E. Iglesias 15586d76d23eSEdgar E. Iglesias /* Insns connected to FSL or AXI stream attached devices. */ 15596d76d23eSEdgar E. Iglesias static void dec_stream(DisasContext *dc) 15606d76d23eSEdgar E. Iglesias { 15616d76d23eSEdgar E. Iglesias TCGv_i32 t_id, t_ctrl; 15626d76d23eSEdgar E. Iglesias int ctrl; 15636d76d23eSEdgar E. Iglesias 1564bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 15656d76d23eSEdgar E. Iglesias return; 15666d76d23eSEdgar E. Iglesias } 15676d76d23eSEdgar E. Iglesias 1568cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 15696d76d23eSEdgar E. Iglesias if (dc->type_b) { 1570cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 15716d76d23eSEdgar E. Iglesias ctrl = dc->imm >> 10; 15726d76d23eSEdgar E. Iglesias } else { 1573cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 15746d76d23eSEdgar E. Iglesias ctrl = dc->imm >> 5; 15756d76d23eSEdgar E. Iglesias } 15766d76d23eSEdgar E. Iglesias 1577cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 15786d76d23eSEdgar E. Iglesias 15796d76d23eSEdgar E. Iglesias if (dc->rd == 0) { 15806d76d23eSEdgar E. Iglesias gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 15816d76d23eSEdgar E. Iglesias } else { 15826d76d23eSEdgar E. Iglesias gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 15836d76d23eSEdgar E. Iglesias } 1584cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1585cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 15866d76d23eSEdgar E. Iglesias } 15876d76d23eSEdgar E. Iglesias 15884acb54baSEdgar E. Iglesias static struct decoder_info { 15894acb54baSEdgar E. Iglesias struct { 15904acb54baSEdgar E. Iglesias uint32_t bits; 15914acb54baSEdgar E. Iglesias uint32_t mask; 15924acb54baSEdgar E. Iglesias }; 15934acb54baSEdgar E. Iglesias void (*dec)(DisasContext *dc); 15944acb54baSEdgar E. Iglesias } decinfo[] = { 15954acb54baSEdgar E. Iglesias {DEC_AND, dec_and}, 15964acb54baSEdgar E. Iglesias {DEC_XOR, dec_xor}, 15974acb54baSEdgar E. Iglesias {DEC_OR, dec_or}, 15984acb54baSEdgar E. Iglesias {DEC_BIT, dec_bit}, 15994acb54baSEdgar E. Iglesias {DEC_BARREL, dec_barrel}, 16004acb54baSEdgar E. Iglesias {DEC_LD, dec_load}, 16014acb54baSEdgar E. Iglesias {DEC_ST, dec_store}, 16024acb54baSEdgar E. Iglesias {DEC_IMM, dec_imm}, 16034acb54baSEdgar E. Iglesias {DEC_BR, dec_br}, 16044acb54baSEdgar E. Iglesias {DEC_BCC, dec_bcc}, 16054acb54baSEdgar E. Iglesias {DEC_RTS, dec_rts}, 16061567a005SEdgar E. Iglesias {DEC_FPU, dec_fpu}, 16074acb54baSEdgar E. Iglesias {DEC_MUL, dec_mul}, 16084acb54baSEdgar E. Iglesias {DEC_DIV, dec_div}, 16094acb54baSEdgar E. Iglesias {DEC_MSR, dec_msr}, 16106d76d23eSEdgar E. Iglesias {DEC_STREAM, dec_stream}, 16114acb54baSEdgar E. Iglesias {{0, 0}, dec_null} 16124acb54baSEdgar E. Iglesias }; 16134acb54baSEdgar E. Iglesias 161444d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir) 16154acb54baSEdgar E. Iglesias { 16164acb54baSEdgar E. Iglesias int i; 16174acb54baSEdgar E. Iglesias 161864254ebaSBlue Swirl dc->ir = ir; 16194acb54baSEdgar E. Iglesias 16204acb54baSEdgar E. Iglesias /* bit 2 seems to indicate insn type. */ 16214acb54baSEdgar E. Iglesias dc->type_b = ir & (1 << 29); 16224acb54baSEdgar E. Iglesias 16234acb54baSEdgar E. Iglesias dc->opcode = EXTRACT_FIELD(ir, 26, 31); 16244acb54baSEdgar E. Iglesias dc->rd = EXTRACT_FIELD(ir, 21, 25); 16254acb54baSEdgar E. Iglesias dc->ra = EXTRACT_FIELD(ir, 16, 20); 16264acb54baSEdgar E. Iglesias dc->rb = EXTRACT_FIELD(ir, 11, 15); 16274acb54baSEdgar E. Iglesias dc->imm = EXTRACT_FIELD(ir, 0, 15); 16284acb54baSEdgar E. Iglesias 16294acb54baSEdgar E. Iglesias /* Large switch for all insns. */ 16304acb54baSEdgar E. Iglesias for (i = 0; i < ARRAY_SIZE(decinfo); i++) { 16314acb54baSEdgar E. Iglesias if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { 16324acb54baSEdgar E. Iglesias decinfo[i].dec(dc); 16334acb54baSEdgar E. Iglesias break; 16344acb54baSEdgar E. Iglesias } 16354acb54baSEdgar E. Iglesias } 16364acb54baSEdgar E. Iglesias } 16374acb54baSEdgar E. Iglesias 1638372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 16394acb54baSEdgar E. Iglesias { 1640372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1641372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1642372122e3SRichard Henderson int bound; 16434acb54baSEdgar E. Iglesias 16440063ebd6SAndreas Färber dc->cpu = cpu; 1645372122e3SRichard Henderson dc->synced_flags = dc->tb_flags = dc->base.tb->flags; 16464acb54baSEdgar E. Iglesias dc->delayed_branch = !!(dc->tb_flags & D_FLAG); 1647372122e3SRichard Henderson dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; 16484acb54baSEdgar E. Iglesias dc->cpustate_changed = 0; 16494acb54baSEdgar E. Iglesias dc->abort_at_next_insn = 0; 1650d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 165120800179SRichard Henderson dc->r0 = NULL; 165220800179SRichard Henderson dc->r0_set = false; 16534acb54baSEdgar E. Iglesias 1654372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1655372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1656a47dddd7SAndreas Färber } 16574acb54baSEdgar E. Iglesias 1658372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 16594acb54baSEdgar E. Iglesias { 1660b933066aSRichard Henderson } 1661b933066aSRichard Henderson 1662372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1663372122e3SRichard Henderson { 1664372122e3SRichard Henderson tcg_gen_insn_start(dcb->pc_next); 1665372122e3SRichard Henderson } 16664acb54baSEdgar E. Iglesias 1667372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1668372122e3SRichard Henderson const CPUBreakpoint *bp) 1669372122e3SRichard Henderson { 1670372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1671372122e3SRichard Henderson 1672372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1673372122e3SRichard Henderson 1674372122e3SRichard Henderson /* 1675372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1676372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1677372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1678372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1679372122e3SRichard Henderson */ 1680372122e3SRichard Henderson dc->base.pc_next += 4; 1681372122e3SRichard Henderson return true; 1682372122e3SRichard Henderson } 1683372122e3SRichard Henderson 1684372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1685372122e3SRichard Henderson { 1686372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1687372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 168844d1432bSRichard Henderson uint32_t ir; 1689372122e3SRichard Henderson 1690372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1691372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1692372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1693372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1694959082fcSRichard Henderson } 16954acb54baSEdgar E. Iglesias 16964acb54baSEdgar E. Iglesias dc->clear_imm = 1; 169744d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 169844d1432bSRichard Henderson if (!decode(dc, ir)) { 169944d1432bSRichard Henderson old_decode(dc, ir); 170044d1432bSRichard Henderson } 170120800179SRichard Henderson 170220800179SRichard Henderson if (dc->r0) { 170320800179SRichard Henderson tcg_temp_free_i32(dc->r0); 170420800179SRichard Henderson dc->r0 = NULL; 170520800179SRichard Henderson dc->r0_set = false; 170620800179SRichard Henderson } 170720800179SRichard Henderson 1708d7ecb757SRichard Henderson if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { 17094acb54baSEdgar E. Iglesias dc->tb_flags &= ~IMM_FLAG; 1710d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1711372122e3SRichard Henderson } 1712d4705ae0SRichard Henderson dc->base.pc_next += 4; 17134acb54baSEdgar E. Iglesias 1714372122e3SRichard Henderson if (dc->delayed_branch && --dc->delayed_branch == 0) { 1715372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 17164acb54baSEdgar E. Iglesias do_rti(dc); 1717372122e3SRichard Henderson } 1718372122e3SRichard Henderson if (dc->tb_flags & DRTB_FLAG) { 17194acb54baSEdgar E. Iglesias do_rtb(dc); 1720372122e3SRichard Henderson } 1721372122e3SRichard Henderson if (dc->tb_flags & DRTE_FLAG) { 17224acb54baSEdgar E. Iglesias do_rte(dc); 1723372122e3SRichard Henderson } 17244acb54baSEdgar E. Iglesias /* Clear the delay slot flag. */ 17254acb54baSEdgar E. Iglesias dc->tb_flags &= ~D_FLAG; 1726372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1727372122e3SRichard Henderson } 1728372122e3SRichard Henderson 1729372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1730372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1731372122e3SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1732372122e3SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1733372122e3SRichard Henderson } 1734372122e3SRichard Henderson } 1735372122e3SRichard Henderson 1736372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1737372122e3SRichard Henderson { 1738372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1739372122e3SRichard Henderson 1740372122e3SRichard Henderson assert(!dc->abort_at_next_insn); 1741372122e3SRichard Henderson 1742372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1743372122e3SRichard Henderson /* We have already exited the TB. */ 1744372122e3SRichard Henderson return; 1745372122e3SRichard Henderson } 1746372122e3SRichard Henderson 1747372122e3SRichard Henderson t_sync_flags(dc); 1748372122e3SRichard Henderson if (dc->tb_flags & D_FLAG) { 1749372122e3SRichard Henderson sync_jmpstate(dc); 1750372122e3SRichard Henderson dc->jmp = JMP_NOJMP; 1751372122e3SRichard Henderson } 1752372122e3SRichard Henderson 1753372122e3SRichard Henderson switch (dc->base.is_jmp) { 1754372122e3SRichard Henderson case DISAS_TOO_MANY: 1755372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1756372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1757372122e3SRichard Henderson return; 1758372122e3SRichard Henderson 1759372122e3SRichard Henderson case DISAS_UPDATE: 1760372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1761372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1762372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1763372122e3SRichard Henderson } else { 1764372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1765372122e3SRichard Henderson } 1766372122e3SRichard Henderson return; 1767372122e3SRichard Henderson 1768372122e3SRichard Henderson case DISAS_JUMP: 1769372122e3SRichard Henderson switch (dc->jmp) { 1770372122e3SRichard Henderson case JMP_INDIRECT: 1771372122e3SRichard Henderson { 1772d4705ae0SRichard Henderson TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); 17730f96e96bSRichard Henderson eval_cond_jmp(dc, cpu_btarget, tmp_pc); 17740f96e96bSRichard Henderson tcg_temp_free_i32(tmp_pc); 1775372122e3SRichard Henderson 1776372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1777372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1778372122e3SRichard Henderson } else { 1779372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1780372122e3SRichard Henderson } 1781372122e3SRichard Henderson } 1782372122e3SRichard Henderson return; 1783372122e3SRichard Henderson 1784372122e3SRichard Henderson case JMP_DIRECT_CC: 1785372122e3SRichard Henderson { 178642a268c2SRichard Henderson TCGLabel *l1 = gen_new_label(); 17879b158558SRichard Henderson tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); 1788d4705ae0SRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 178923979dc5SEdgar E. Iglesias gen_set_label(l1); 1790372122e3SRichard Henderson } 1791372122e3SRichard Henderson /* fall through */ 1792372122e3SRichard Henderson 1793372122e3SRichard Henderson case JMP_DIRECT: 179423979dc5SEdgar E. Iglesias gen_goto_tb(dc, 0, dc->jmp_pc); 1795372122e3SRichard Henderson return; 17964acb54baSEdgar E. Iglesias } 1797372122e3SRichard Henderson /* fall through */ 17984acb54baSEdgar E. Iglesias 1799a2b80dbdSRichard Henderson default: 1800a2b80dbdSRichard Henderson g_assert_not_reached(); 18014acb54baSEdgar E. Iglesias } 18024acb54baSEdgar E. Iglesias } 18030a7df5daSRichard Henderson 1804372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1805372122e3SRichard Henderson { 1806372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1807372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 18084acb54baSEdgar E. Iglesias } 1809372122e3SRichard Henderson 1810372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1811372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1812372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1813372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1814372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1815372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1816372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1817372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1818372122e3SRichard Henderson }; 1819372122e3SRichard Henderson 1820372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1821372122e3SRichard Henderson { 1822372122e3SRichard Henderson DisasContext dc; 1823372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 18244acb54baSEdgar E. Iglesias } 18254acb54baSEdgar E. Iglesias 182690c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 18274acb54baSEdgar E. Iglesias { 1828878096eeSAndreas Färber MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1829878096eeSAndreas Färber CPUMBState *env = &cpu->env; 18304acb54baSEdgar E. Iglesias int i; 18314acb54baSEdgar E. Iglesias 183290c84c56SMarkus Armbruster if (!env) { 18334acb54baSEdgar E. Iglesias return; 183490c84c56SMarkus Armbruster } 18354acb54baSEdgar E. Iglesias 18360f96e96bSRichard Henderson qemu_fprintf(f, "IN: PC=%x %s\n", 183776e8187dSRichard Henderson env->pc, lookup_symbol(env->pc)); 18386efd5599SRichard Henderson qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " 1839eb2022b7SRichard Henderson "imm=%x iflags=%x fsr=%x rbtr=%x\n", 184078e9caf2SRichard Henderson env->msr, env->esr, env->ear, 1841eb2022b7SRichard Henderson env->imm, env->iflags, env->fsr, env->btr); 18420f96e96bSRichard Henderson qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 18434acb54baSEdgar E. Iglesias env->btaken, env->btarget, 18442e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18452e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18462e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18472e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18482ead1b18SJoe Komlodi for (i = 0; i < 12; i++) { 18492ead1b18SJoe Komlodi qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); 18502ead1b18SJoe Komlodi if ((i + 1) % 4 == 0) { 18512ead1b18SJoe Komlodi qemu_fprintf(f, "\n"); 18522ead1b18SJoe Komlodi } 18532ead1b18SJoe Komlodi } 185417c52a43SEdgar E. Iglesias 18552ead1b18SJoe Komlodi /* Registers that aren't modeled are reported as 0 */ 185639db007eSRichard Henderson qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " 1857af20a93aSRichard Henderson "rtlblo=0 rtlbhi=0\n", env->edr); 18582ead1b18SJoe Komlodi qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); 18594acb54baSEdgar E. Iglesias for (i = 0; i < 32; i++) { 186090c84c56SMarkus Armbruster qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); 18614acb54baSEdgar E. Iglesias if ((i + 1) % 4 == 0) 186290c84c56SMarkus Armbruster qemu_fprintf(f, "\n"); 18634acb54baSEdgar E. Iglesias } 186490c84c56SMarkus Armbruster qemu_fprintf(f, "\n\n"); 18654acb54baSEdgar E. Iglesias } 18664acb54baSEdgar E. Iglesias 1867cd0c24f9SAndreas Färber void mb_tcg_init(void) 1868cd0c24f9SAndreas Färber { 1869480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1870480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 18714acb54baSEdgar E. Iglesias 1872480d29a8SRichard Henderson static const struct { 1873480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1874480d29a8SRichard Henderson } i32s[] = { 1875480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1876480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1877480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1878480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1879480d29a8SRichard Henderson 1880480d29a8SRichard Henderson SP(pc), 1881480d29a8SRichard Henderson SP(msr), 18821074c0fbSRichard Henderson SP(msr_c), 1883480d29a8SRichard Henderson SP(imm), 1884480d29a8SRichard Henderson SP(iflags), 1885480d29a8SRichard Henderson SP(btaken), 1886480d29a8SRichard Henderson SP(btarget), 1887480d29a8SRichard Henderson SP(res_val), 1888480d29a8SRichard Henderson }; 1889480d29a8SRichard Henderson 1890480d29a8SRichard Henderson #undef R 1891480d29a8SRichard Henderson #undef SP 1892480d29a8SRichard Henderson 1893480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1894480d29a8SRichard Henderson *i32s[i].var = 1895480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 18964acb54baSEdgar E. Iglesias } 189776e8187dSRichard Henderson 1898480d29a8SRichard Henderson cpu_res_addr = 1899480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 19004acb54baSEdgar E. Iglesias } 19014acb54baSEdgar E. Iglesias 1902bad729e2SRichard Henderson void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1903bad729e2SRichard Henderson target_ulong *data) 19044acb54baSEdgar E. Iglesias { 190576e8187dSRichard Henderson env->pc = data[0]; 19064acb54baSEdgar E. Iglesias } 1907