1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * Xilinx MicroBlaze emulation for qemu: main translation routines. 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2009 Edgar E. Iglesias. 5fcf5ef2aSThomas Huth * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 6fcf5ef2aSThomas Huth * 7fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or 8fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public 9fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either 10fcf5ef2aSThomas Huth * version 2 of the License, or (at your option) any later version. 11fcf5ef2aSThomas Huth * 12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fcf5ef2aSThomas Huth * Lesser General Public License for more details. 16fcf5ef2aSThomas Huth * 17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fcf5ef2aSThomas Huth */ 20fcf5ef2aSThomas Huth 21fcf5ef2aSThomas Huth #include "qemu/osdep.h" 22fcf5ef2aSThomas Huth #include "cpu.h" 23fcf5ef2aSThomas Huth #include "disas/disas.h" 24fcf5ef2aSThomas Huth #include "exec/exec-all.h" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 26fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 27fcf5ef2aSThomas Huth #include "microblaze-decode.h" 28fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h" 29fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 3077fc6f5eSLluís Vilanova #include "exec/translator.h" 3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 32fcf5ef2aSThomas Huth 33fcf5ef2aSThomas Huth #include "trace-tcg.h" 34fcf5ef2aSThomas Huth #include "exec/log.h" 35fcf5ef2aSThomas Huth 36fcf5ef2aSThomas Huth 37fcf5ef2aSThomas Huth #define SIM_COMPAT 0 38fcf5ef2aSThomas Huth #define DISAS_GNU 1 39fcf5ef2aSThomas Huth #define DISAS_MB 1 40fcf5ef2aSThomas Huth #if DISAS_MB && !SIM_COMPAT 41fcf5ef2aSThomas Huth # define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) 42fcf5ef2aSThomas Huth #else 43fcf5ef2aSThomas Huth # define LOG_DIS(...) do { } while (0) 44fcf5ef2aSThomas Huth #endif 45fcf5ef2aSThomas Huth 46fcf5ef2aSThomas Huth #define D(x) 47fcf5ef2aSThomas Huth 48fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 49fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 50fcf5ef2aSThomas Huth 5177fc6f5eSLluís Vilanova /* is_jmp field values */ 5277fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 5377fc6f5eSLluís Vilanova #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ 5477fc6f5eSLluís Vilanova #define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */ 5577fc6f5eSLluís Vilanova 56cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 570f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 583e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 599b158558SRichard Henderson static TCGv_i32 cpu_imm; 609b158558SRichard Henderson static TCGv_i32 cpu_btaken; 610f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 629b158558SRichard Henderson static TCGv_i32 cpu_iflags; 639b158558SRichard Henderson static TCGv cpu_res_addr; 649b158558SRichard Henderson static TCGv_i32 cpu_res_val; 65fcf5ef2aSThomas Huth 66fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 67fcf5ef2aSThomas Huth 68fcf5ef2aSThomas Huth /* This is the state at translation time. */ 69fcf5ef2aSThomas Huth typedef struct DisasContext { 70fcf5ef2aSThomas Huth MicroBlazeCPU *cpu; 71cfeea807SEdgar E. Iglesias uint32_t pc; 72fcf5ef2aSThomas Huth 73fcf5ef2aSThomas Huth /* Decoder. */ 74fcf5ef2aSThomas Huth int type_b; 75fcf5ef2aSThomas Huth uint32_t ir; 76fcf5ef2aSThomas Huth uint8_t opcode; 77fcf5ef2aSThomas Huth uint8_t rd, ra, rb; 78fcf5ef2aSThomas Huth uint16_t imm; 79fcf5ef2aSThomas Huth 80fcf5ef2aSThomas Huth unsigned int cpustate_changed; 81fcf5ef2aSThomas Huth unsigned int delayed_branch; 82fcf5ef2aSThomas Huth unsigned int tb_flags, synced_flags; /* tb dependent flags. */ 83fcf5ef2aSThomas Huth unsigned int clear_imm; 84fcf5ef2aSThomas Huth int is_jmp; 85fcf5ef2aSThomas Huth 86fcf5ef2aSThomas Huth #define JMP_NOJMP 0 87fcf5ef2aSThomas Huth #define JMP_DIRECT 1 88fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2 89fcf5ef2aSThomas Huth #define JMP_INDIRECT 3 90fcf5ef2aSThomas Huth unsigned int jmp; 91fcf5ef2aSThomas Huth uint32_t jmp_pc; 92fcf5ef2aSThomas Huth 93fcf5ef2aSThomas Huth int abort_at_next_insn; 94fcf5ef2aSThomas Huth struct TranslationBlock *tb; 95fcf5ef2aSThomas Huth int singlestep_enabled; 96fcf5ef2aSThomas Huth } DisasContext; 97fcf5ef2aSThomas Huth 98fcf5ef2aSThomas Huth static inline void t_sync_flags(DisasContext *dc) 99fcf5ef2aSThomas Huth { 100fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 101fcf5ef2aSThomas Huth if (dc->tb_flags != dc->synced_flags) { 1029b158558SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags); 103fcf5ef2aSThomas Huth dc->synced_flags = dc->tb_flags; 104fcf5ef2aSThomas Huth } 105fcf5ef2aSThomas Huth } 106fcf5ef2aSThomas Huth 10741ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 108fcf5ef2aSThomas Huth { 109fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 110fcf5ef2aSThomas Huth 111fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 112fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 113fcf5ef2aSThomas Huth dc->is_jmp = DISAS_UPDATE; 114fcf5ef2aSThomas Huth } 115fcf5ef2aSThomas Huth 11641ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11741ba37c4SRichard Henderson { 11841ba37c4SRichard Henderson t_sync_flags(dc); 11941ba37c4SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->pc); 12041ba37c4SRichard Henderson gen_raise_exception(dc, index); 12141ba37c4SRichard Henderson } 12241ba37c4SRichard Henderson 12341ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12441ba37c4SRichard Henderson { 12541ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12641ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12741ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12841ba37c4SRichard Henderson 12941ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 13041ba37c4SRichard Henderson } 13141ba37c4SRichard Henderson 132fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 133fcf5ef2aSThomas Huth { 134fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 135fcf5ef2aSThomas Huth return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 136fcf5ef2aSThomas Huth #else 137fcf5ef2aSThomas Huth return true; 138fcf5ef2aSThomas Huth #endif 139fcf5ef2aSThomas Huth } 140fcf5ef2aSThomas Huth 141fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 142fcf5ef2aSThomas Huth { 143fcf5ef2aSThomas Huth if (use_goto_tb(dc, dest)) { 144fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1450f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 14607ea28b4SRichard Henderson tcg_gen_exit_tb(dc->tb, n); 147fcf5ef2aSThomas Huth } else { 1480f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 14907ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 150fcf5ef2aSThomas Huth } 151fcf5ef2aSThomas Huth } 152fcf5ef2aSThomas Huth 153cfeea807SEdgar E. Iglesias static void read_carry(DisasContext *dc, TCGv_i32 d) 154fcf5ef2aSThomas Huth { 1553e0e16aeSRichard Henderson tcg_gen_shri_i32(d, cpu_msr, 31); 156fcf5ef2aSThomas Huth } 157fcf5ef2aSThomas Huth 158fcf5ef2aSThomas Huth /* 159fcf5ef2aSThomas Huth * write_carry sets the carry bits in MSR based on bit 0 of v. 160fcf5ef2aSThomas Huth * v[31:1] are ignored. 161fcf5ef2aSThomas Huth */ 162cfeea807SEdgar E. Iglesias static void write_carry(DisasContext *dc, TCGv_i32 v) 163fcf5ef2aSThomas Huth { 1640a22f8cfSEdgar E. Iglesias /* Deposit bit 0 into MSR_C and the alias MSR_CC. */ 1653e0e16aeSRichard Henderson tcg_gen_deposit_i32(cpu_msr, cpu_msr, v, 2, 1); 1663e0e16aeSRichard Henderson tcg_gen_deposit_i32(cpu_msr, cpu_msr, v, 31, 1); 167fcf5ef2aSThomas Huth } 168fcf5ef2aSThomas Huth 169fcf5ef2aSThomas Huth static void write_carryi(DisasContext *dc, bool carry) 170fcf5ef2aSThomas Huth { 171cfeea807SEdgar E. Iglesias TCGv_i32 t0 = tcg_temp_new_i32(); 172cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t0, carry); 173fcf5ef2aSThomas Huth write_carry(dc, t0); 174cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 175fcf5ef2aSThomas Huth } 176fcf5ef2aSThomas Huth 177bdfc1e88SEdgar E. Iglesias /* 1789ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1799ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1809ba8cd45SEdgar E. Iglesias */ 1819ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1829ba8cd45SEdgar E. Iglesias { 1839ba8cd45SEdgar E. Iglesias if (cond && (dc->tb_flags & MSR_EE_FLAG) 1845143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 18541ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1869ba8cd45SEdgar E. Iglesias } 1879ba8cd45SEdgar E. Iglesias return cond; 1889ba8cd45SEdgar E. Iglesias } 1899ba8cd45SEdgar E. Iglesias 1909ba8cd45SEdgar E. Iglesias /* 191bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 192bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 193bdfc1e88SEdgar E. Iglesias */ 194bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 195bdfc1e88SEdgar E. Iglesias { 196bdfc1e88SEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 197bdfc1e88SEdgar E. Iglesias bool cond_user = cond && mem_index == MMU_USER_IDX; 198bdfc1e88SEdgar E. Iglesias 199bdfc1e88SEdgar E. Iglesias if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { 20041ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 201bdfc1e88SEdgar E. Iglesias } 202bdfc1e88SEdgar E. Iglesias return cond_user; 203bdfc1e88SEdgar E. Iglesias } 204bdfc1e88SEdgar E. Iglesias 205fcf5ef2aSThomas Huth /* True if ALU operand b is a small immediate that may deserve 206fcf5ef2aSThomas Huth faster treatment. */ 207fcf5ef2aSThomas Huth static inline int dec_alu_op_b_is_small_imm(DisasContext *dc) 208fcf5ef2aSThomas Huth { 209fcf5ef2aSThomas Huth /* Immediate insn without the imm prefix ? */ 210fcf5ef2aSThomas Huth return dc->type_b && !(dc->tb_flags & IMM_FLAG); 211fcf5ef2aSThomas Huth } 212fcf5ef2aSThomas Huth 213cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) 214fcf5ef2aSThomas Huth { 215fcf5ef2aSThomas Huth if (dc->type_b) { 216fcf5ef2aSThomas Huth if (dc->tb_flags & IMM_FLAG) 2179b158558SRichard Henderson tcg_gen_ori_i32(cpu_imm, cpu_imm, dc->imm); 218fcf5ef2aSThomas Huth else 2199b158558SRichard Henderson tcg_gen_movi_i32(cpu_imm, (int32_t)((int16_t)dc->imm)); 2209b158558SRichard Henderson return &cpu_imm; 221fcf5ef2aSThomas Huth } else 222fcf5ef2aSThomas Huth return &cpu_R[dc->rb]; 223fcf5ef2aSThomas Huth } 224fcf5ef2aSThomas Huth 225fcf5ef2aSThomas Huth static void dec_add(DisasContext *dc) 226fcf5ef2aSThomas Huth { 227fcf5ef2aSThomas Huth unsigned int k, c; 228cfeea807SEdgar E. Iglesias TCGv_i32 cf; 229fcf5ef2aSThomas Huth 230fcf5ef2aSThomas Huth k = dc->opcode & 4; 231fcf5ef2aSThomas Huth c = dc->opcode & 2; 232fcf5ef2aSThomas Huth 233fcf5ef2aSThomas Huth LOG_DIS("add%s%s%s r%d r%d r%d\n", 234fcf5ef2aSThomas Huth dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "", 235fcf5ef2aSThomas Huth dc->rd, dc->ra, dc->rb); 236fcf5ef2aSThomas Huth 237fcf5ef2aSThomas Huth /* Take care of the easy cases first. */ 238fcf5ef2aSThomas Huth if (k) { 239fcf5ef2aSThomas Huth /* k - keep carry, no need to update MSR. */ 240fcf5ef2aSThomas Huth /* If rd == r0, it's a nop. */ 241fcf5ef2aSThomas Huth if (dc->rd) { 242cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 243fcf5ef2aSThomas Huth 244fcf5ef2aSThomas Huth if (c) { 245fcf5ef2aSThomas Huth /* c - Add carry into the result. */ 246cfeea807SEdgar E. Iglesias cf = tcg_temp_new_i32(); 247fcf5ef2aSThomas Huth 248fcf5ef2aSThomas Huth read_carry(dc, cf); 249cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); 250cfeea807SEdgar E. Iglesias tcg_temp_free_i32(cf); 251fcf5ef2aSThomas Huth } 252fcf5ef2aSThomas Huth } 253fcf5ef2aSThomas Huth return; 254fcf5ef2aSThomas Huth } 255fcf5ef2aSThomas Huth 256fcf5ef2aSThomas Huth /* From now on, we can assume k is zero. So we need to update MSR. */ 257fcf5ef2aSThomas Huth /* Extract carry. */ 258cfeea807SEdgar E. Iglesias cf = tcg_temp_new_i32(); 259fcf5ef2aSThomas Huth if (c) { 260fcf5ef2aSThomas Huth read_carry(dc, cf); 261fcf5ef2aSThomas Huth } else { 262cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cf, 0); 263fcf5ef2aSThomas Huth } 264fcf5ef2aSThomas Huth 265fcf5ef2aSThomas Huth if (dc->rd) { 266cfeea807SEdgar E. Iglesias TCGv_i32 ncf = tcg_temp_new_i32(); 267fcf5ef2aSThomas Huth gen_helper_carry(ncf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf); 268cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 269cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); 270fcf5ef2aSThomas Huth write_carry(dc, ncf); 271cfeea807SEdgar E. Iglesias tcg_temp_free_i32(ncf); 272fcf5ef2aSThomas Huth } else { 273fcf5ef2aSThomas Huth gen_helper_carry(cf, cpu_R[dc->ra], *(dec_alu_op_b(dc)), cf); 274fcf5ef2aSThomas Huth write_carry(dc, cf); 275fcf5ef2aSThomas Huth } 276cfeea807SEdgar E. Iglesias tcg_temp_free_i32(cf); 277fcf5ef2aSThomas Huth } 278fcf5ef2aSThomas Huth 279fcf5ef2aSThomas Huth static void dec_sub(DisasContext *dc) 280fcf5ef2aSThomas Huth { 281fcf5ef2aSThomas Huth unsigned int u, cmp, k, c; 282cfeea807SEdgar E. Iglesias TCGv_i32 cf, na; 283fcf5ef2aSThomas Huth 284fcf5ef2aSThomas Huth u = dc->imm & 2; 285fcf5ef2aSThomas Huth k = dc->opcode & 4; 286fcf5ef2aSThomas Huth c = dc->opcode & 2; 287fcf5ef2aSThomas Huth cmp = (dc->imm & 1) && (!dc->type_b) && k; 288fcf5ef2aSThomas Huth 289fcf5ef2aSThomas Huth if (cmp) { 290fcf5ef2aSThomas Huth LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir); 291fcf5ef2aSThomas Huth if (dc->rd) { 292fcf5ef2aSThomas Huth if (u) 293fcf5ef2aSThomas Huth gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 294fcf5ef2aSThomas Huth else 295fcf5ef2aSThomas Huth gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 296fcf5ef2aSThomas Huth } 297fcf5ef2aSThomas Huth return; 298fcf5ef2aSThomas Huth } 299fcf5ef2aSThomas Huth 300fcf5ef2aSThomas Huth LOG_DIS("sub%s%s r%d, r%d r%d\n", 301fcf5ef2aSThomas Huth k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb); 302fcf5ef2aSThomas Huth 303fcf5ef2aSThomas Huth /* Take care of the easy cases first. */ 304fcf5ef2aSThomas Huth if (k) { 305fcf5ef2aSThomas Huth /* k - keep carry, no need to update MSR. */ 306fcf5ef2aSThomas Huth /* If rd == r0, it's a nop. */ 307fcf5ef2aSThomas Huth if (dc->rd) { 308cfeea807SEdgar E. Iglesias tcg_gen_sub_i32(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); 309fcf5ef2aSThomas Huth 310fcf5ef2aSThomas Huth if (c) { 311fcf5ef2aSThomas Huth /* c - Add carry into the result. */ 312cfeea807SEdgar E. Iglesias cf = tcg_temp_new_i32(); 313fcf5ef2aSThomas Huth 314fcf5ef2aSThomas Huth read_carry(dc, cf); 315cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); 316cfeea807SEdgar E. Iglesias tcg_temp_free_i32(cf); 317fcf5ef2aSThomas Huth } 318fcf5ef2aSThomas Huth } 319fcf5ef2aSThomas Huth return; 320fcf5ef2aSThomas Huth } 321fcf5ef2aSThomas Huth 322fcf5ef2aSThomas Huth /* From now on, we can assume k is zero. So we need to update MSR. */ 323fcf5ef2aSThomas Huth /* Extract carry. And complement a into na. */ 324cfeea807SEdgar E. Iglesias cf = tcg_temp_new_i32(); 325cfeea807SEdgar E. Iglesias na = tcg_temp_new_i32(); 326fcf5ef2aSThomas Huth if (c) { 327fcf5ef2aSThomas Huth read_carry(dc, cf); 328fcf5ef2aSThomas Huth } else { 329cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cf, 1); 330fcf5ef2aSThomas Huth } 331fcf5ef2aSThomas Huth 332fcf5ef2aSThomas Huth /* d = b + ~a + c. carry defaults to 1. */ 333cfeea807SEdgar E. Iglesias tcg_gen_not_i32(na, cpu_R[dc->ra]); 334fcf5ef2aSThomas Huth 335fcf5ef2aSThomas Huth if (dc->rd) { 336cfeea807SEdgar E. Iglesias TCGv_i32 ncf = tcg_temp_new_i32(); 337fcf5ef2aSThomas Huth gen_helper_carry(ncf, na, *(dec_alu_op_b(dc)), cf); 338cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], na, *(dec_alu_op_b(dc))); 339cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); 340fcf5ef2aSThomas Huth write_carry(dc, ncf); 341cfeea807SEdgar E. Iglesias tcg_temp_free_i32(ncf); 342fcf5ef2aSThomas Huth } else { 343fcf5ef2aSThomas Huth gen_helper_carry(cf, na, *(dec_alu_op_b(dc)), cf); 344fcf5ef2aSThomas Huth write_carry(dc, cf); 345fcf5ef2aSThomas Huth } 346cfeea807SEdgar E. Iglesias tcg_temp_free_i32(cf); 347cfeea807SEdgar E. Iglesias tcg_temp_free_i32(na); 348fcf5ef2aSThomas Huth } 349fcf5ef2aSThomas Huth 350fcf5ef2aSThomas Huth static void dec_pattern(DisasContext *dc) 351fcf5ef2aSThomas Huth { 352fcf5ef2aSThomas Huth unsigned int mode; 353fcf5ef2aSThomas Huth 3549ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { 3559ba8cd45SEdgar E. Iglesias return; 356fcf5ef2aSThomas Huth } 357fcf5ef2aSThomas Huth 358fcf5ef2aSThomas Huth mode = dc->opcode & 3; 359fcf5ef2aSThomas Huth switch (mode) { 360fcf5ef2aSThomas Huth case 0: 361fcf5ef2aSThomas Huth /* pcmpbf. */ 362fcf5ef2aSThomas Huth LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); 363fcf5ef2aSThomas Huth if (dc->rd) 364fcf5ef2aSThomas Huth gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 365fcf5ef2aSThomas Huth break; 366fcf5ef2aSThomas Huth case 2: 367fcf5ef2aSThomas Huth LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); 368fcf5ef2aSThomas Huth if (dc->rd) { 369cfeea807SEdgar E. Iglesias tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd], 370fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 371fcf5ef2aSThomas Huth } 372fcf5ef2aSThomas Huth break; 373fcf5ef2aSThomas Huth case 3: 374fcf5ef2aSThomas Huth LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); 375fcf5ef2aSThomas Huth if (dc->rd) { 376cfeea807SEdgar E. Iglesias tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd], 377fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 378fcf5ef2aSThomas Huth } 379fcf5ef2aSThomas Huth break; 380fcf5ef2aSThomas Huth default: 381fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), 382fcf5ef2aSThomas Huth "unsupported pattern insn opcode=%x\n", dc->opcode); 383fcf5ef2aSThomas Huth break; 384fcf5ef2aSThomas Huth } 385fcf5ef2aSThomas Huth } 386fcf5ef2aSThomas Huth 387fcf5ef2aSThomas Huth static void dec_and(DisasContext *dc) 388fcf5ef2aSThomas Huth { 389fcf5ef2aSThomas Huth unsigned int not; 390fcf5ef2aSThomas Huth 391fcf5ef2aSThomas Huth if (!dc->type_b && (dc->imm & (1 << 10))) { 392fcf5ef2aSThomas Huth dec_pattern(dc); 393fcf5ef2aSThomas Huth return; 394fcf5ef2aSThomas Huth } 395fcf5ef2aSThomas Huth 396fcf5ef2aSThomas Huth not = dc->opcode & (1 << 1); 397fcf5ef2aSThomas Huth LOG_DIS("and%s\n", not ? "n" : ""); 398fcf5ef2aSThomas Huth 399fcf5ef2aSThomas Huth if (!dc->rd) 400fcf5ef2aSThomas Huth return; 401fcf5ef2aSThomas Huth 402fcf5ef2aSThomas Huth if (not) { 403cfeea807SEdgar E. Iglesias tcg_gen_andc_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 404fcf5ef2aSThomas Huth } else 405cfeea807SEdgar E. Iglesias tcg_gen_and_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 406fcf5ef2aSThomas Huth } 407fcf5ef2aSThomas Huth 408fcf5ef2aSThomas Huth static void dec_or(DisasContext *dc) 409fcf5ef2aSThomas Huth { 410fcf5ef2aSThomas Huth if (!dc->type_b && (dc->imm & (1 << 10))) { 411fcf5ef2aSThomas Huth dec_pattern(dc); 412fcf5ef2aSThomas Huth return; 413fcf5ef2aSThomas Huth } 414fcf5ef2aSThomas Huth 415fcf5ef2aSThomas Huth LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm); 416fcf5ef2aSThomas Huth if (dc->rd) 417cfeea807SEdgar E. Iglesias tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 418fcf5ef2aSThomas Huth } 419fcf5ef2aSThomas Huth 420fcf5ef2aSThomas Huth static void dec_xor(DisasContext *dc) 421fcf5ef2aSThomas Huth { 422fcf5ef2aSThomas Huth if (!dc->type_b && (dc->imm & (1 << 10))) { 423fcf5ef2aSThomas Huth dec_pattern(dc); 424fcf5ef2aSThomas Huth return; 425fcf5ef2aSThomas Huth } 426fcf5ef2aSThomas Huth 427fcf5ef2aSThomas Huth LOG_DIS("xor r%d\n", dc->rd); 428fcf5ef2aSThomas Huth if (dc->rd) 429cfeea807SEdgar E. Iglesias tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 430fcf5ef2aSThomas Huth } 431fcf5ef2aSThomas Huth 432cfeea807SEdgar E. Iglesias static inline void msr_read(DisasContext *dc, TCGv_i32 d) 433fcf5ef2aSThomas Huth { 4343e0e16aeSRichard Henderson tcg_gen_mov_i32(d, cpu_msr); 435fcf5ef2aSThomas Huth } 436fcf5ef2aSThomas Huth 437cfeea807SEdgar E. Iglesias static inline void msr_write(DisasContext *dc, TCGv_i32 v) 438fcf5ef2aSThomas Huth { 439fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 4403e0e16aeSRichard Henderson /* PVR bit is not writable, and is never set. */ 4413e0e16aeSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~MSR_PVR); 442fcf5ef2aSThomas Huth } 443fcf5ef2aSThomas Huth 444fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc) 445fcf5ef2aSThomas Huth { 446fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 447cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 4482023e9a3SEdgar E. Iglesias unsigned int sr, rn; 449f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 450fcf5ef2aSThomas Huth 4512023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 4522023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 4532023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 454fcf5ef2aSThomas Huth dc->type_b = 1; 4552023e9a3SEdgar E. Iglesias if (to) { 456fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 457f0f7e7f7SEdgar E. Iglesias } 458f0f7e7f7SEdgar E. Iglesias 459f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 460f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 461f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 462f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 463f0f7e7f7SEdgar E. Iglesias 464f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 4652023e9a3SEdgar E. Iglesias } 466fcf5ef2aSThomas Huth 467fcf5ef2aSThomas Huth /* msrclr and msrset. */ 4682023e9a3SEdgar E. Iglesias if (clrset) { 4692023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 470fcf5ef2aSThomas Huth 471fcf5ef2aSThomas Huth LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set", 472fcf5ef2aSThomas Huth dc->rd, dc->imm); 473fcf5ef2aSThomas Huth 47456837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 475fcf5ef2aSThomas Huth /* nop??? */ 476fcf5ef2aSThomas Huth return; 477fcf5ef2aSThomas Huth } 478fcf5ef2aSThomas Huth 479bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 480fcf5ef2aSThomas Huth return; 481fcf5ef2aSThomas Huth } 482fcf5ef2aSThomas Huth 483fcf5ef2aSThomas Huth if (dc->rd) 484fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 485fcf5ef2aSThomas Huth 486cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 487cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 488fcf5ef2aSThomas Huth msr_read(dc, t0); 489cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 490fcf5ef2aSThomas Huth 491fcf5ef2aSThomas Huth if (clr) { 492cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 493cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 494fcf5ef2aSThomas Huth } else 495cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 496fcf5ef2aSThomas Huth msr_write(dc, t0); 497cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 498cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 4990f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->pc + 4); 500fcf5ef2aSThomas Huth dc->is_jmp = DISAS_UPDATE; 501fcf5ef2aSThomas Huth return; 502fcf5ef2aSThomas Huth } 503fcf5ef2aSThomas Huth 504bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 505fcf5ef2aSThomas Huth return; 506fcf5ef2aSThomas Huth } 507fcf5ef2aSThomas Huth 508fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 509fcf5ef2aSThomas Huth /* Catch read/writes to the mmu block. */ 510fcf5ef2aSThomas Huth if ((sr & ~0xff) == 0x1000) { 511f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 51205a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 51305a9a651SEdgar E. Iglesias 514fcf5ef2aSThomas Huth sr &= 7; 51505a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 516fcf5ef2aSThomas Huth LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm); 51705a9a651SEdgar E. Iglesias if (to) { 518f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 51905a9a651SEdgar E. Iglesias } else { 520f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 52105a9a651SEdgar E. Iglesias } 52205a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 523f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 524fcf5ef2aSThomas Huth return; 525fcf5ef2aSThomas Huth } 526fcf5ef2aSThomas Huth #endif 527fcf5ef2aSThomas Huth 528fcf5ef2aSThomas Huth if (to) { 529fcf5ef2aSThomas Huth LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm); 530fcf5ef2aSThomas Huth switch (sr) { 531aa28e6d4SRichard Henderson case SR_PC: 532fcf5ef2aSThomas Huth break; 533aa28e6d4SRichard Henderson case SR_MSR: 534fcf5ef2aSThomas Huth msr_write(dc, cpu_R[dc->ra]); 535fcf5ef2aSThomas Huth break; 536351527b7SEdgar E. Iglesias case SR_EAR: 537dbdb77c4SRichard Henderson { 538dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 539dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 540dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 541dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 542dbdb77c4SRichard Henderson } 543aa28e6d4SRichard Henderson break; 544351527b7SEdgar E. Iglesias case SR_ESR: 54541ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 54641ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 547aa28e6d4SRichard Henderson break; 548ab6dd380SEdgar E. Iglesias case SR_FSR: 54986017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 55086017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 551aa28e6d4SRichard Henderson break; 552aa28e6d4SRichard Henderson case SR_BTR: 553ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 554ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 555aa28e6d4SRichard Henderson break; 556aa28e6d4SRichard Henderson case SR_EDR: 55739db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 55839db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 559fcf5ef2aSThomas Huth break; 560fcf5ef2aSThomas Huth case 0x800: 561cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 562cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 563fcf5ef2aSThomas Huth break; 564fcf5ef2aSThomas Huth case 0x802: 565cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 566cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 567fcf5ef2aSThomas Huth break; 568fcf5ef2aSThomas Huth default: 569fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 570fcf5ef2aSThomas Huth break; 571fcf5ef2aSThomas Huth } 572fcf5ef2aSThomas Huth } else { 573fcf5ef2aSThomas Huth LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm); 574fcf5ef2aSThomas Huth 575fcf5ef2aSThomas Huth switch (sr) { 576aa28e6d4SRichard Henderson case SR_PC: 577cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc); 578fcf5ef2aSThomas Huth break; 579aa28e6d4SRichard Henderson case SR_MSR: 580fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 581fcf5ef2aSThomas Huth break; 582351527b7SEdgar E. Iglesias case SR_EAR: 583dbdb77c4SRichard Henderson { 584dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 585dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 586a1b48e3aSEdgar E. Iglesias if (extended) { 587dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 588aa28e6d4SRichard Henderson } else { 589dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 590dbdb77c4SRichard Henderson } 591dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 592a1b48e3aSEdgar E. Iglesias } 593aa28e6d4SRichard Henderson break; 594351527b7SEdgar E. Iglesias case SR_ESR: 59541ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 59641ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 597aa28e6d4SRichard Henderson break; 598351527b7SEdgar E. Iglesias case SR_FSR: 59986017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 60086017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 601aa28e6d4SRichard Henderson break; 602351527b7SEdgar E. Iglesias case SR_BTR: 603ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 604ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 605aa28e6d4SRichard Henderson break; 6067cdae31dSTong Ho case SR_EDR: 60739db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 60839db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 609fcf5ef2aSThomas Huth break; 610fcf5ef2aSThomas Huth case 0x800: 611cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 612cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 613fcf5ef2aSThomas Huth break; 614fcf5ef2aSThomas Huth case 0x802: 615cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 616cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 617fcf5ef2aSThomas Huth break; 618351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 619fcf5ef2aSThomas Huth rn = sr & 0xf; 620cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 621fcf5ef2aSThomas Huth cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 622fcf5ef2aSThomas Huth break; 623fcf5ef2aSThomas Huth default: 624fcf5ef2aSThomas Huth cpu_abort(cs, "unknown mfs reg %x\n", sr); 625fcf5ef2aSThomas Huth break; 626fcf5ef2aSThomas Huth } 627fcf5ef2aSThomas Huth } 628fcf5ef2aSThomas Huth 629fcf5ef2aSThomas Huth if (dc->rd == 0) { 630cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 631fcf5ef2aSThomas Huth } 632fcf5ef2aSThomas Huth } 633fcf5ef2aSThomas Huth 634fcf5ef2aSThomas Huth /* Multiplier unit. */ 635fcf5ef2aSThomas Huth static void dec_mul(DisasContext *dc) 636fcf5ef2aSThomas Huth { 637cfeea807SEdgar E. Iglesias TCGv_i32 tmp; 638fcf5ef2aSThomas Huth unsigned int subcode; 639fcf5ef2aSThomas Huth 6409ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_hw_mul)) { 641fcf5ef2aSThomas Huth return; 642fcf5ef2aSThomas Huth } 643fcf5ef2aSThomas Huth 644fcf5ef2aSThomas Huth subcode = dc->imm & 3; 645fcf5ef2aSThomas Huth 646fcf5ef2aSThomas Huth if (dc->type_b) { 647fcf5ef2aSThomas Huth LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm); 648cfeea807SEdgar E. Iglesias tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 649fcf5ef2aSThomas Huth return; 650fcf5ef2aSThomas Huth } 651fcf5ef2aSThomas Huth 652fcf5ef2aSThomas Huth /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */ 6539b964318SEdgar E. Iglesias if (subcode >= 1 && subcode <= 3 && dc->cpu->cfg.use_hw_mul < 2) { 654fcf5ef2aSThomas Huth /* nop??? */ 655fcf5ef2aSThomas Huth } 656fcf5ef2aSThomas Huth 657cfeea807SEdgar E. Iglesias tmp = tcg_temp_new_i32(); 658fcf5ef2aSThomas Huth switch (subcode) { 659fcf5ef2aSThomas Huth case 0: 660fcf5ef2aSThomas Huth LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); 661cfeea807SEdgar E. Iglesias tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 662fcf5ef2aSThomas Huth break; 663fcf5ef2aSThomas Huth case 1: 664fcf5ef2aSThomas Huth LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); 665cfeea807SEdgar E. Iglesias tcg_gen_muls2_i32(tmp, cpu_R[dc->rd], 666cfeea807SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 667fcf5ef2aSThomas Huth break; 668fcf5ef2aSThomas Huth case 2: 669fcf5ef2aSThomas Huth LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); 670cfeea807SEdgar E. Iglesias tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd], 671cfeea807SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 672fcf5ef2aSThomas Huth break; 673fcf5ef2aSThomas Huth case 3: 674fcf5ef2aSThomas Huth LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); 675cfeea807SEdgar E. Iglesias tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 676fcf5ef2aSThomas Huth break; 677fcf5ef2aSThomas Huth default: 678fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode); 679fcf5ef2aSThomas Huth break; 680fcf5ef2aSThomas Huth } 681cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tmp); 682fcf5ef2aSThomas Huth } 683fcf5ef2aSThomas Huth 684fcf5ef2aSThomas Huth /* Div unit. */ 685fcf5ef2aSThomas Huth static void dec_div(DisasContext *dc) 686fcf5ef2aSThomas Huth { 687fcf5ef2aSThomas Huth unsigned int u; 688fcf5ef2aSThomas Huth 689fcf5ef2aSThomas Huth u = dc->imm & 2; 690fcf5ef2aSThomas Huth LOG_DIS("div\n"); 691fcf5ef2aSThomas Huth 6929ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_div)) { 6939ba8cd45SEdgar E. Iglesias return; 694fcf5ef2aSThomas Huth } 695fcf5ef2aSThomas Huth 696fcf5ef2aSThomas Huth if (u) 697fcf5ef2aSThomas Huth gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), 698fcf5ef2aSThomas Huth cpu_R[dc->ra]); 699fcf5ef2aSThomas Huth else 700fcf5ef2aSThomas Huth gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), 701fcf5ef2aSThomas Huth cpu_R[dc->ra]); 702fcf5ef2aSThomas Huth if (!dc->rd) 703cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[dc->rd], 0); 704fcf5ef2aSThomas Huth } 705fcf5ef2aSThomas Huth 706fcf5ef2aSThomas Huth static void dec_barrel(DisasContext *dc) 707fcf5ef2aSThomas Huth { 708cfeea807SEdgar E. Iglesias TCGv_i32 t0; 709faa48d74SEdgar E. Iglesias unsigned int imm_w, imm_s; 710d09b2585SEdgar E. Iglesias bool s, t, e = false, i = false; 711fcf5ef2aSThomas Huth 7129ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) { 713fcf5ef2aSThomas Huth return; 714fcf5ef2aSThomas Huth } 715fcf5ef2aSThomas Huth 716faa48d74SEdgar E. Iglesias if (dc->type_b) { 717faa48d74SEdgar E. Iglesias /* Insert and extract are only available in immediate mode. */ 718d09b2585SEdgar E. Iglesias i = extract32(dc->imm, 15, 1); 719faa48d74SEdgar E. Iglesias e = extract32(dc->imm, 14, 1); 720faa48d74SEdgar E. Iglesias } 721e3e84983SEdgar E. Iglesias s = extract32(dc->imm, 10, 1); 722e3e84983SEdgar E. Iglesias t = extract32(dc->imm, 9, 1); 723faa48d74SEdgar E. Iglesias imm_w = extract32(dc->imm, 6, 5); 724faa48d74SEdgar E. Iglesias imm_s = extract32(dc->imm, 0, 5); 725fcf5ef2aSThomas Huth 726faa48d74SEdgar E. Iglesias LOG_DIS("bs%s%s%s r%d r%d r%d\n", 727faa48d74SEdgar E. Iglesias e ? "e" : "", 728fcf5ef2aSThomas Huth s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb); 729fcf5ef2aSThomas Huth 730faa48d74SEdgar E. Iglesias if (e) { 731faa48d74SEdgar E. Iglesias if (imm_w + imm_s > 32 || imm_w == 0) { 732faa48d74SEdgar E. Iglesias /* These inputs have an undefined behavior. */ 733faa48d74SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 734faa48d74SEdgar E. Iglesias imm_w, imm_s); 735faa48d74SEdgar E. Iglesias } else { 736faa48d74SEdgar E. Iglesias tcg_gen_extract_i32(cpu_R[dc->rd], cpu_R[dc->ra], imm_s, imm_w); 737faa48d74SEdgar E. Iglesias } 738d09b2585SEdgar E. Iglesias } else if (i) { 739d09b2585SEdgar E. Iglesias int width = imm_w - imm_s + 1; 740d09b2585SEdgar E. Iglesias 741d09b2585SEdgar E. Iglesias if (imm_w < imm_s) { 742d09b2585SEdgar E. Iglesias /* These inputs have an undefined behavior. */ 743d09b2585SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 744d09b2585SEdgar E. Iglesias imm_w, imm_s); 745d09b2585SEdgar E. Iglesias } else { 746d09b2585SEdgar E. Iglesias tcg_gen_deposit_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_R[dc->ra], 747d09b2585SEdgar E. Iglesias imm_s, width); 748d09b2585SEdgar E. Iglesias } 749faa48d74SEdgar E. Iglesias } else { 750cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 751fcf5ef2aSThomas Huth 752cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc))); 753cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, 31); 754fcf5ef2aSThomas Huth 7552acf6d53SEdgar E. Iglesias if (s) { 756cfeea807SEdgar E. Iglesias tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7572acf6d53SEdgar E. Iglesias } else { 7582acf6d53SEdgar E. Iglesias if (t) { 759cfeea807SEdgar E. Iglesias tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7602acf6d53SEdgar E. Iglesias } else { 761cfeea807SEdgar E. Iglesias tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 762fcf5ef2aSThomas Huth } 763fcf5ef2aSThomas Huth } 764cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 7652acf6d53SEdgar E. Iglesias } 766faa48d74SEdgar E. Iglesias } 767fcf5ef2aSThomas Huth 768fcf5ef2aSThomas Huth static void dec_bit(DisasContext *dc) 769fcf5ef2aSThomas Huth { 770fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 771cfeea807SEdgar E. Iglesias TCGv_i32 t0; 772fcf5ef2aSThomas Huth unsigned int op; 773fcf5ef2aSThomas Huth 774fcf5ef2aSThomas Huth op = dc->ir & ((1 << 9) - 1); 775fcf5ef2aSThomas Huth switch (op) { 776fcf5ef2aSThomas Huth case 0x21: 777fcf5ef2aSThomas Huth /* src. */ 778cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 779fcf5ef2aSThomas Huth 780fcf5ef2aSThomas Huth LOG_DIS("src r%d r%d\n", dc->rd, dc->ra); 7813e0e16aeSRichard Henderson tcg_gen_andi_i32(t0, cpu_msr, MSR_CC); 782fcf5ef2aSThomas Huth write_carry(dc, cpu_R[dc->ra]); 783fcf5ef2aSThomas Huth if (dc->rd) { 784cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 785cfeea807SEdgar E. Iglesias tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0); 786fcf5ef2aSThomas Huth } 787cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 788fcf5ef2aSThomas Huth break; 789fcf5ef2aSThomas Huth 790fcf5ef2aSThomas Huth case 0x1: 791fcf5ef2aSThomas Huth case 0x41: 792fcf5ef2aSThomas Huth /* srl. */ 793fcf5ef2aSThomas Huth LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra); 794fcf5ef2aSThomas Huth 795fcf5ef2aSThomas Huth /* Update carry. Note that write carry only looks at the LSB. */ 796fcf5ef2aSThomas Huth write_carry(dc, cpu_R[dc->ra]); 797fcf5ef2aSThomas Huth if (dc->rd) { 798fcf5ef2aSThomas Huth if (op == 0x41) 799cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 800fcf5ef2aSThomas Huth else 801cfeea807SEdgar E. Iglesias tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 802fcf5ef2aSThomas Huth } 803fcf5ef2aSThomas Huth break; 804fcf5ef2aSThomas Huth case 0x60: 805fcf5ef2aSThomas Huth LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra); 806fcf5ef2aSThomas Huth tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 807fcf5ef2aSThomas Huth break; 808fcf5ef2aSThomas Huth case 0x61: 809fcf5ef2aSThomas Huth LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra); 810fcf5ef2aSThomas Huth tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 811fcf5ef2aSThomas Huth break; 812fcf5ef2aSThomas Huth case 0x64: 813fcf5ef2aSThomas Huth case 0x66: 814fcf5ef2aSThomas Huth case 0x74: 815fcf5ef2aSThomas Huth case 0x76: 816fcf5ef2aSThomas Huth /* wdc. */ 817fcf5ef2aSThomas Huth LOG_DIS("wdc r%d\n", dc->ra); 818bdfc1e88SEdgar E. Iglesias trap_userspace(dc, true); 819fcf5ef2aSThomas Huth break; 820fcf5ef2aSThomas Huth case 0x68: 821fcf5ef2aSThomas Huth /* wic. */ 822fcf5ef2aSThomas Huth LOG_DIS("wic r%d\n", dc->ra); 823bdfc1e88SEdgar E. Iglesias trap_userspace(dc, true); 824fcf5ef2aSThomas Huth break; 825fcf5ef2aSThomas Huth case 0xe0: 8269ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { 8279ba8cd45SEdgar E. Iglesias return; 828fcf5ef2aSThomas Huth } 8298fc5239eSEdgar E. Iglesias if (dc->cpu->cfg.use_pcmp_instr) { 8305318420cSRichard Henderson tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32); 831fcf5ef2aSThomas Huth } 832fcf5ef2aSThomas Huth break; 833fcf5ef2aSThomas Huth case 0x1e0: 834fcf5ef2aSThomas Huth /* swapb */ 835fcf5ef2aSThomas Huth LOG_DIS("swapb r%d r%d\n", dc->rd, dc->ra); 836fcf5ef2aSThomas Huth tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 837fcf5ef2aSThomas Huth break; 838fcf5ef2aSThomas Huth case 0x1e2: 839fcf5ef2aSThomas Huth /*swaph */ 840fcf5ef2aSThomas Huth LOG_DIS("swaph r%d r%d\n", dc->rd, dc->ra); 841fcf5ef2aSThomas Huth tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16); 842fcf5ef2aSThomas Huth break; 843fcf5ef2aSThomas Huth default: 844fcf5ef2aSThomas Huth cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", 845fcf5ef2aSThomas Huth dc->pc, op, dc->rd, dc->ra, dc->rb); 846fcf5ef2aSThomas Huth break; 847fcf5ef2aSThomas Huth } 848fcf5ef2aSThomas Huth } 849fcf5ef2aSThomas Huth 850fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc) 851fcf5ef2aSThomas Huth { 852fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 853fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT) { 8549b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 855fcf5ef2aSThomas Huth } 856fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 8570f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 858fcf5ef2aSThomas Huth } 859fcf5ef2aSThomas Huth } 860fcf5ef2aSThomas Huth 861fcf5ef2aSThomas Huth static void dec_imm(DisasContext *dc) 862fcf5ef2aSThomas Huth { 863fcf5ef2aSThomas Huth LOG_DIS("imm %x\n", dc->imm << 16); 8649b158558SRichard Henderson tcg_gen_movi_i32(cpu_imm, (dc->imm << 16)); 865fcf5ef2aSThomas Huth dc->tb_flags |= IMM_FLAG; 866fcf5ef2aSThomas Huth dc->clear_imm = 0; 867fcf5ef2aSThomas Huth } 868fcf5ef2aSThomas Huth 869d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) 870fcf5ef2aSThomas Huth { 8710e9033c8SEdgar E. Iglesias bool extimm = dc->tb_flags & IMM_FLAG; 8720e9033c8SEdgar E. Iglesias /* Should be set to true if r1 is used by loadstores. */ 8730e9033c8SEdgar E. Iglesias bool stackprot = false; 874403322eaSEdgar E. Iglesias TCGv_i32 t32; 875fcf5ef2aSThomas Huth 876fcf5ef2aSThomas Huth /* All load/stores use ra. */ 877fcf5ef2aSThomas Huth if (dc->ra == 1 && dc->cpu->cfg.stackprot) { 8780e9033c8SEdgar E. Iglesias stackprot = true; 879fcf5ef2aSThomas Huth } 880fcf5ef2aSThomas Huth 881fcf5ef2aSThomas Huth /* Treat the common cases first. */ 882fcf5ef2aSThomas Huth if (!dc->type_b) { 883d248e1beSEdgar E. Iglesias if (ea) { 884d248e1beSEdgar E. Iglesias int addr_size = dc->cpu->cfg.addr_size; 885d248e1beSEdgar E. Iglesias 886d248e1beSEdgar E. Iglesias if (addr_size == 32) { 887d248e1beSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 888d248e1beSEdgar E. Iglesias return; 889d248e1beSEdgar E. Iglesias } 890d248e1beSEdgar E. Iglesias 891d248e1beSEdgar E. Iglesias tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]); 892d248e1beSEdgar E. Iglesias if (addr_size < 64) { 893d248e1beSEdgar E. Iglesias /* Mask off out of range bits. */ 894d248e1beSEdgar E. Iglesias tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size)); 895d248e1beSEdgar E. Iglesias } 896d248e1beSEdgar E. Iglesias return; 897d248e1beSEdgar E. Iglesias } 898d248e1beSEdgar E. Iglesias 8990dc4af5cSEdgar E. Iglesias /* If any of the regs is r0, set t to the value of the other reg. */ 900fcf5ef2aSThomas Huth if (dc->ra == 0) { 901403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 9020dc4af5cSEdgar E. Iglesias return; 903fcf5ef2aSThomas Huth } else if (dc->rb == 0) { 904403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]); 9050dc4af5cSEdgar E. Iglesias return; 906fcf5ef2aSThomas Huth } 907fcf5ef2aSThomas Huth 908fcf5ef2aSThomas Huth if (dc->rb == 1 && dc->cpu->cfg.stackprot) { 9090e9033c8SEdgar E. Iglesias stackprot = true; 910fcf5ef2aSThomas Huth } 911fcf5ef2aSThomas Huth 912403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 913403322eaSEdgar E. Iglesias tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]); 914403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 915403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 916fcf5ef2aSThomas Huth 917fcf5ef2aSThomas Huth if (stackprot) { 9180a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 919fcf5ef2aSThomas Huth } 9200dc4af5cSEdgar E. Iglesias return; 921fcf5ef2aSThomas Huth } 922fcf5ef2aSThomas Huth /* Immediate. */ 923403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 924fcf5ef2aSThomas Huth if (!extimm) { 925f7a66e3aSEdgar E. Iglesias tcg_gen_addi_i32(t32, cpu_R[dc->ra], (int16_t)dc->imm); 926403322eaSEdgar E. Iglesias } else { 927403322eaSEdgar E. Iglesias tcg_gen_add_i32(t32, cpu_R[dc->ra], *(dec_alu_op_b(dc))); 928403322eaSEdgar E. Iglesias } 929403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 930403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 931fcf5ef2aSThomas Huth 932fcf5ef2aSThomas Huth if (stackprot) { 9330a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 934fcf5ef2aSThomas Huth } 9350dc4af5cSEdgar E. Iglesias return; 936fcf5ef2aSThomas Huth } 937fcf5ef2aSThomas Huth 938fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc) 939fcf5ef2aSThomas Huth { 940403322eaSEdgar E. Iglesias TCGv_i32 v; 941403322eaSEdgar E. Iglesias TCGv addr; 9428534063aSEdgar E. Iglesias unsigned int size; 943d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 944d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 94514776ab5STony Nguyen MemOp mop; 946fcf5ef2aSThomas Huth 947fcf5ef2aSThomas Huth mop = dc->opcode & 3; 948fcf5ef2aSThomas Huth size = 1 << mop; 949fcf5ef2aSThomas Huth if (!dc->type_b) { 950d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 9518534063aSEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 9528534063aSEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 953fcf5ef2aSThomas Huth } 954fcf5ef2aSThomas Huth mop |= MO_TE; 955fcf5ef2aSThomas Huth if (rev) { 956fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 957fcf5ef2aSThomas Huth } 958fcf5ef2aSThomas Huth 9599ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 960fcf5ef2aSThomas Huth return; 961fcf5ef2aSThomas Huth } 962fcf5ef2aSThomas Huth 963d248e1beSEdgar E. Iglesias if (trap_userspace(dc, ea)) { 964d248e1beSEdgar E. Iglesias return; 965d248e1beSEdgar E. Iglesias } 966d248e1beSEdgar E. Iglesias 967d248e1beSEdgar E. Iglesias LOG_DIS("l%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "", 968d248e1beSEdgar E. Iglesias ex ? "x" : "", 969d248e1beSEdgar E. Iglesias ea ? "ea" : ""); 970fcf5ef2aSThomas Huth 971fcf5ef2aSThomas Huth t_sync_flags(dc); 972403322eaSEdgar E. Iglesias addr = tcg_temp_new(); 973d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 974d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 975d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 976fcf5ef2aSThomas Huth 977fcf5ef2aSThomas Huth /* 978fcf5ef2aSThomas Huth * When doing reverse accesses we need to do two things. 979fcf5ef2aSThomas Huth * 980fcf5ef2aSThomas Huth * 1. Reverse the address wrt endianness. 981fcf5ef2aSThomas Huth * 2. Byteswap the data lanes on the way back into the CPU core. 982fcf5ef2aSThomas Huth */ 983fcf5ef2aSThomas Huth if (rev && size != 4) { 984fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 985fcf5ef2aSThomas Huth switch (size) { 986fcf5ef2aSThomas Huth case 1: 987fcf5ef2aSThomas Huth { 988a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 989fcf5ef2aSThomas Huth break; 990fcf5ef2aSThomas Huth } 991fcf5ef2aSThomas Huth 992fcf5ef2aSThomas Huth case 2: 993fcf5ef2aSThomas Huth /* 00 -> 10 994fcf5ef2aSThomas Huth 10 -> 00. */ 995403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 996fcf5ef2aSThomas Huth break; 997fcf5ef2aSThomas Huth default: 998fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 999fcf5ef2aSThomas Huth break; 1000fcf5ef2aSThomas Huth } 1001fcf5ef2aSThomas Huth } 1002fcf5ef2aSThomas Huth 1003fcf5ef2aSThomas Huth /* lwx does not throw unaligned access errors, so force alignment */ 1004fcf5ef2aSThomas Huth if (ex) { 1005403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 1006fcf5ef2aSThomas Huth } 1007fcf5ef2aSThomas Huth 1008fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 1009fcf5ef2aSThomas Huth sync_jmpstate(dc); 1010fcf5ef2aSThomas Huth 1011fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 1012fcf5ef2aSThomas Huth /* 1013fcf5ef2aSThomas Huth * Microblaze gives MMU faults priority over faults due to 1014fcf5ef2aSThomas Huth * unaligned addresses. That's why we speculatively do the load 1015fcf5ef2aSThomas Huth * into v. If the load succeeds, we verify alignment of the 1016fcf5ef2aSThomas Huth * address and if that succeeds we write into the destination reg. 1017fcf5ef2aSThomas Huth */ 1018cfeea807SEdgar E. Iglesias v = tcg_temp_new_i32(); 1019d248e1beSEdgar E. Iglesias tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); 1020fcf5ef2aSThomas Huth 10211507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1022a6338015SEdgar E. Iglesias TCGv_i32 t0 = tcg_const_i32(0); 1023a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1024a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1025a6338015SEdgar E. Iglesias 10260f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->pc); 1027a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t0, tsize); 1028a6338015SEdgar E. Iglesias 1029a6338015SEdgar E. Iglesias tcg_temp_free_i32(t0); 1030a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1031a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1032fcf5ef2aSThomas Huth } 1033fcf5ef2aSThomas Huth 1034fcf5ef2aSThomas Huth if (ex) { 10359b158558SRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 10369b158558SRichard Henderson tcg_gen_mov_i32(cpu_res_val, v); 1037fcf5ef2aSThomas Huth } 1038fcf5ef2aSThomas Huth if (dc->rd) { 1039cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(cpu_R[dc->rd], v); 1040fcf5ef2aSThomas Huth } 1041cfeea807SEdgar E. Iglesias tcg_temp_free_i32(v); 1042fcf5ef2aSThomas Huth 1043fcf5ef2aSThomas Huth if (ex) { /* lwx */ 1044fcf5ef2aSThomas Huth /* no support for AXI exclusive so always clear C */ 1045fcf5ef2aSThomas Huth write_carryi(dc, 0); 1046fcf5ef2aSThomas Huth } 1047fcf5ef2aSThomas Huth 1048403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1049fcf5ef2aSThomas Huth } 1050fcf5ef2aSThomas Huth 1051fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc) 1052fcf5ef2aSThomas Huth { 1053403322eaSEdgar E. Iglesias TCGv addr; 1054fcf5ef2aSThomas Huth TCGLabel *swx_skip = NULL; 1055b51b3d43SEdgar E. Iglesias unsigned int size; 1056d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 1057d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 105814776ab5STony Nguyen MemOp mop; 1059fcf5ef2aSThomas Huth 1060fcf5ef2aSThomas Huth mop = dc->opcode & 3; 1061fcf5ef2aSThomas Huth size = 1 << mop; 1062fcf5ef2aSThomas Huth if (!dc->type_b) { 1063d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 1064b51b3d43SEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 1065b51b3d43SEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 1066fcf5ef2aSThomas Huth } 1067fcf5ef2aSThomas Huth mop |= MO_TE; 1068fcf5ef2aSThomas Huth if (rev) { 1069fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 1070fcf5ef2aSThomas Huth } 1071fcf5ef2aSThomas Huth 10729ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 1073fcf5ef2aSThomas Huth return; 1074fcf5ef2aSThomas Huth } 1075fcf5ef2aSThomas Huth 1076d248e1beSEdgar E. Iglesias trap_userspace(dc, ea); 1077d248e1beSEdgar E. Iglesias 1078d248e1beSEdgar E. Iglesias LOG_DIS("s%d%s%s%s%s\n", size, dc->type_b ? "i" : "", rev ? "r" : "", 1079d248e1beSEdgar E. Iglesias ex ? "x" : "", 1080d248e1beSEdgar E. Iglesias ea ? "ea" : ""); 1081fcf5ef2aSThomas Huth t_sync_flags(dc); 1082fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 1083fcf5ef2aSThomas Huth sync_jmpstate(dc); 10840dc4af5cSEdgar E. Iglesias /* SWX needs a temp_local. */ 1085403322eaSEdgar E. Iglesias addr = ex ? tcg_temp_local_new() : tcg_temp_new(); 1086d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 1087d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 1088d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 1089fcf5ef2aSThomas Huth 1090fcf5ef2aSThomas Huth if (ex) { /* swx */ 1091cfeea807SEdgar E. Iglesias TCGv_i32 tval; 1092fcf5ef2aSThomas Huth 1093fcf5ef2aSThomas Huth /* swx does not throw unaligned access errors, so force alignment */ 1094403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 1095fcf5ef2aSThomas Huth 1096fcf5ef2aSThomas Huth write_carryi(dc, 1); 1097fcf5ef2aSThomas Huth swx_skip = gen_new_label(); 10989b158558SRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); 1099fcf5ef2aSThomas Huth 1100071cdc67SEdgar E. Iglesias /* 1101071cdc67SEdgar E. Iglesias * Compare the value loaded at lwx with current contents of 1102071cdc67SEdgar E. Iglesias * the reserved location. 1103071cdc67SEdgar E. Iglesias */ 1104cfeea807SEdgar E. Iglesias tval = tcg_temp_new_i32(); 1105071cdc67SEdgar E. Iglesias 11069b158558SRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val, 1107071cdc67SEdgar E. Iglesias cpu_R[dc->rd], mem_index, 1108071cdc67SEdgar E. Iglesias mop); 1109071cdc67SEdgar E. Iglesias 11109b158558SRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); 1111fcf5ef2aSThomas Huth write_carryi(dc, 0); 1112cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tval); 1113fcf5ef2aSThomas Huth } 1114fcf5ef2aSThomas Huth 1115fcf5ef2aSThomas Huth if (rev && size != 4) { 1116fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 1117fcf5ef2aSThomas Huth switch (size) { 1118fcf5ef2aSThomas Huth case 1: 1119fcf5ef2aSThomas Huth { 1120a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 1121fcf5ef2aSThomas Huth break; 1122fcf5ef2aSThomas Huth } 1123fcf5ef2aSThomas Huth 1124fcf5ef2aSThomas Huth case 2: 1125fcf5ef2aSThomas Huth /* 00 -> 10 1126fcf5ef2aSThomas Huth 10 -> 00. */ 1127fcf5ef2aSThomas Huth /* Force addr into the temp. */ 1128403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 1129fcf5ef2aSThomas Huth break; 1130fcf5ef2aSThomas Huth default: 1131fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 1132fcf5ef2aSThomas Huth break; 1133fcf5ef2aSThomas Huth } 1134fcf5ef2aSThomas Huth } 1135071cdc67SEdgar E. Iglesias 1136071cdc67SEdgar E. Iglesias if (!ex) { 1137d248e1beSEdgar E. Iglesias tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); 1138071cdc67SEdgar E. Iglesias } 1139fcf5ef2aSThomas Huth 1140fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 11411507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1142a6338015SEdgar E. Iglesias TCGv_i32 t1 = tcg_const_i32(1); 1143a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1144a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1145a6338015SEdgar E. Iglesias 11460f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->pc); 1147fcf5ef2aSThomas Huth /* FIXME: if the alignment is wrong, we should restore the value 1148fcf5ef2aSThomas Huth * in memory. One possible way to achieve this is to probe 1149fcf5ef2aSThomas Huth * the MMU prior to the memaccess, thay way we could put 1150fcf5ef2aSThomas Huth * the alignment checks in between the probe and the mem 1151fcf5ef2aSThomas Huth * access. 1152fcf5ef2aSThomas Huth */ 1153a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t1, tsize); 1154a6338015SEdgar E. Iglesias 1155a6338015SEdgar E. Iglesias tcg_temp_free_i32(t1); 1156a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1157a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1158fcf5ef2aSThomas Huth } 1159fcf5ef2aSThomas Huth 1160fcf5ef2aSThomas Huth if (ex) { 1161fcf5ef2aSThomas Huth gen_set_label(swx_skip); 1162fcf5ef2aSThomas Huth } 1163fcf5ef2aSThomas Huth 1164403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1165fcf5ef2aSThomas Huth } 1166fcf5ef2aSThomas Huth 1167fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc, 11689e6e1828SEdgar E. Iglesias TCGv_i32 d, TCGv_i32 a) 1169fcf5ef2aSThomas Huth { 1170d89b86e9SEdgar E. Iglesias static const int mb_to_tcg_cc[] = { 1171d89b86e9SEdgar E. Iglesias [CC_EQ] = TCG_COND_EQ, 1172d89b86e9SEdgar E. Iglesias [CC_NE] = TCG_COND_NE, 1173d89b86e9SEdgar E. Iglesias [CC_LT] = TCG_COND_LT, 1174d89b86e9SEdgar E. Iglesias [CC_LE] = TCG_COND_LE, 1175d89b86e9SEdgar E. Iglesias [CC_GE] = TCG_COND_GE, 1176d89b86e9SEdgar E. Iglesias [CC_GT] = TCG_COND_GT, 1177d89b86e9SEdgar E. Iglesias }; 1178d89b86e9SEdgar E. Iglesias 1179fcf5ef2aSThomas Huth switch (cc) { 1180fcf5ef2aSThomas Huth case CC_EQ: 1181fcf5ef2aSThomas Huth case CC_NE: 1182fcf5ef2aSThomas Huth case CC_LT: 1183fcf5ef2aSThomas Huth case CC_LE: 1184fcf5ef2aSThomas Huth case CC_GE: 1185fcf5ef2aSThomas Huth case CC_GT: 11869e6e1828SEdgar E. Iglesias tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); 1187fcf5ef2aSThomas Huth break; 1188fcf5ef2aSThomas Huth default: 1189fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); 1190fcf5ef2aSThomas Huth break; 1191fcf5ef2aSThomas Huth } 1192fcf5ef2aSThomas Huth } 1193fcf5ef2aSThomas Huth 11940f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) 1195fcf5ef2aSThomas Huth { 11960f96e96bSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 1197e956caf2SEdgar E. Iglesias 11980f96e96bSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, 11999b158558SRichard Henderson cpu_btaken, zero, 1200e956caf2SEdgar E. Iglesias pc_true, pc_false); 1201e956caf2SEdgar E. Iglesias 12020f96e96bSRichard Henderson tcg_temp_free_i32(zero); 1203fcf5ef2aSThomas Huth } 1204fcf5ef2aSThomas Huth 1205f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1206f91c60f0SEdgar E. Iglesias { 1207f91c60f0SEdgar E. Iglesias TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)); 1208f91c60f0SEdgar E. Iglesias 1209f91c60f0SEdgar E. Iglesias dc->delayed_branch = 2; 1210f91c60f0SEdgar E. Iglesias dc->tb_flags |= D_FLAG; 1211f91c60f0SEdgar E. Iglesias 1212f91c60f0SEdgar E. Iglesias tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm)); 1213f91c60f0SEdgar E. Iglesias tcg_temp_free_i32(tmp); 1214f91c60f0SEdgar E. Iglesias } 1215f91c60f0SEdgar E. Iglesias 1216fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc) 1217fcf5ef2aSThomas Huth { 1218fcf5ef2aSThomas Huth unsigned int cc; 1219fcf5ef2aSThomas Huth unsigned int dslot; 1220fcf5ef2aSThomas Huth 1221fcf5ef2aSThomas Huth cc = EXTRACT_FIELD(dc->ir, 21, 23); 1222fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 25); 1223fcf5ef2aSThomas Huth LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm); 1224fcf5ef2aSThomas Huth 1225fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1226fcf5ef2aSThomas Huth if (dslot) { 1227f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1228fcf5ef2aSThomas Huth } 1229fcf5ef2aSThomas Huth 1230fcf5ef2aSThomas Huth if (dec_alu_op_b_is_small_imm(dc)) { 1231fcf5ef2aSThomas Huth int32_t offset = (int32_t)((int16_t)dc->imm); /* sign-extend. */ 1232fcf5ef2aSThomas Huth 12330f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->pc + offset); 1234fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT_CC; 1235fcf5ef2aSThomas Huth dc->jmp_pc = dc->pc + offset; 1236fcf5ef2aSThomas Huth } else { 1237fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 12380f96e96bSRichard Henderson tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc); 1239fcf5ef2aSThomas Huth } 12409b158558SRichard Henderson eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); 1241fcf5ef2aSThomas Huth } 1242fcf5ef2aSThomas Huth 1243fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc) 1244fcf5ef2aSThomas Huth { 1245fcf5ef2aSThomas Huth unsigned int dslot, link, abs, mbar; 1246fcf5ef2aSThomas Huth 1247fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 20); 1248fcf5ef2aSThomas Huth abs = dc->ir & (1 << 19); 1249fcf5ef2aSThomas Huth link = dc->ir & (1 << 18); 1250fcf5ef2aSThomas Huth 1251fcf5ef2aSThomas Huth /* Memory barrier. */ 1252fcf5ef2aSThomas Huth mbar = (dc->ir >> 16) & 31; 1253fcf5ef2aSThomas Huth if (mbar == 2 && dc->imm == 4) { 1254badcbf9dSEdgar E. Iglesias uint16_t mbar_imm = dc->rd; 1255badcbf9dSEdgar E. Iglesias 12566f3c458bSEdgar E. Iglesias LOG_DIS("mbar %d\n", mbar_imm); 12576f3c458bSEdgar E. Iglesias 12583f172744SEdgar E. Iglesias /* Data access memory barrier. */ 12593f172744SEdgar E. Iglesias if ((mbar_imm & 2) == 0) { 12603f172744SEdgar E. Iglesias tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 12613f172744SEdgar E. Iglesias } 12623f172744SEdgar E. Iglesias 1263fcf5ef2aSThomas Huth /* mbar IMM & 16 decodes to sleep. */ 1264badcbf9dSEdgar E. Iglesias if (mbar_imm & 16) { 126541ba37c4SRichard Henderson TCGv_i32 tmp_1; 1266fcf5ef2aSThomas Huth 1267fcf5ef2aSThomas Huth LOG_DIS("sleep\n"); 1268fcf5ef2aSThomas Huth 1269b4919e7dSEdgar E. Iglesias if (trap_userspace(dc, true)) { 1270b4919e7dSEdgar E. Iglesias /* Sleep is a privileged instruction. */ 1271b4919e7dSEdgar E. Iglesias return; 1272b4919e7dSEdgar E. Iglesias } 1273b4919e7dSEdgar E. Iglesias 1274fcf5ef2aSThomas Huth t_sync_flags(dc); 127541ba37c4SRichard Henderson 127641ba37c4SRichard Henderson tmp_1 = tcg_const_i32(1); 1277fcf5ef2aSThomas Huth tcg_gen_st_i32(tmp_1, cpu_env, 1278fcf5ef2aSThomas Huth -offsetof(MicroBlazeCPU, env) 1279fcf5ef2aSThomas Huth +offsetof(CPUState, halted)); 1280fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp_1); 128141ba37c4SRichard Henderson 128241ba37c4SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->pc + 4); 128341ba37c4SRichard Henderson 128441ba37c4SRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1285fcf5ef2aSThomas Huth return; 1286fcf5ef2aSThomas Huth } 1287fcf5ef2aSThomas Huth /* Break the TB. */ 1288fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 1289fcf5ef2aSThomas Huth return; 1290fcf5ef2aSThomas Huth } 1291fcf5ef2aSThomas Huth 1292fcf5ef2aSThomas Huth LOG_DIS("br%s%s%s%s imm=%x\n", 1293fcf5ef2aSThomas Huth abs ? "a" : "", link ? "l" : "", 1294fcf5ef2aSThomas Huth dc->type_b ? "i" : "", dslot ? "d" : "", 1295fcf5ef2aSThomas Huth dc->imm); 1296fcf5ef2aSThomas Huth 1297fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1298fcf5ef2aSThomas Huth if (dslot) { 1299f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1300fcf5ef2aSThomas Huth } 1301fcf5ef2aSThomas Huth if (link && dc->rd) 1302cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[dc->rd], dc->pc); 1303fcf5ef2aSThomas Huth 1304fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 1305fcf5ef2aSThomas Huth if (abs) { 13069b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 13070f96e96bSRichard Henderson tcg_gen_mov_i32(cpu_btarget, *(dec_alu_op_b(dc))); 1308fcf5ef2aSThomas Huth if (link && !dslot) { 130941ba37c4SRichard Henderson if (!(dc->tb_flags & IMM_FLAG) && 131041ba37c4SRichard Henderson (dc->imm == 8 || dc->imm == 0x18)) { 131141ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 131241ba37c4SRichard Henderson } 1313fcf5ef2aSThomas Huth if (dc->imm == 0) { 1314bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 1315fcf5ef2aSThomas Huth return; 1316fcf5ef2aSThomas Huth } 131741ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1318fcf5ef2aSThomas Huth } 1319fcf5ef2aSThomas Huth } 1320fcf5ef2aSThomas Huth } else { 1321fcf5ef2aSThomas Huth if (dec_alu_op_b_is_small_imm(dc)) { 1322fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT; 1323fcf5ef2aSThomas Huth dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm); 1324fcf5ef2aSThomas Huth } else { 13259b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 13260f96e96bSRichard Henderson tcg_gen_addi_i32(cpu_btarget, *dec_alu_op_b(dc), dc->pc); 1327fcf5ef2aSThomas Huth } 1328fcf5ef2aSThomas Huth } 1329fcf5ef2aSThomas Huth } 1330fcf5ef2aSThomas Huth 1331fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc) 1332fcf5ef2aSThomas Huth { 1333cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1334cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1335cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13363e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13370a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 13380a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1339cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1340fcf5ef2aSThomas Huth 1341cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1342cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1343fcf5ef2aSThomas Huth msr_write(dc, t1); 1344cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1345cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1346fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1347fcf5ef2aSThomas Huth } 1348fcf5ef2aSThomas Huth 1349fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc) 1350fcf5ef2aSThomas Huth { 1351cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1352cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1353cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13543e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13550a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1356cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1357cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1358fcf5ef2aSThomas Huth 1359cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1360cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1361fcf5ef2aSThomas Huth msr_write(dc, t1); 1362cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1363cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1364fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1365fcf5ef2aSThomas Huth } 1366fcf5ef2aSThomas Huth 1367fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc) 1368fcf5ef2aSThomas Huth { 1369cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1370cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1371cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1372fcf5ef2aSThomas Huth 13733e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13740a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1375cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1376cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1377cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1378fcf5ef2aSThomas Huth 1379cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1380cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1381fcf5ef2aSThomas Huth msr_write(dc, t1); 1382cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1383cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1384fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1385fcf5ef2aSThomas Huth } 1386fcf5ef2aSThomas Huth 1387fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc) 1388fcf5ef2aSThomas Huth { 1389fcf5ef2aSThomas Huth unsigned int b_bit, i_bit, e_bit; 1390fcf5ef2aSThomas Huth 1391fcf5ef2aSThomas Huth i_bit = dc->ir & (1 << 21); 1392fcf5ef2aSThomas Huth b_bit = dc->ir & (1 << 22); 1393fcf5ef2aSThomas Huth e_bit = dc->ir & (1 << 23); 1394fcf5ef2aSThomas Huth 1395bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1396bdfc1e88SEdgar E. Iglesias return; 1397bdfc1e88SEdgar E. Iglesias } 1398bdfc1e88SEdgar E. Iglesias 1399f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1400fcf5ef2aSThomas Huth 1401fcf5ef2aSThomas Huth if (i_bit) { 1402fcf5ef2aSThomas Huth LOG_DIS("rtid ir=%x\n", dc->ir); 1403fcf5ef2aSThomas Huth dc->tb_flags |= DRTI_FLAG; 1404fcf5ef2aSThomas Huth } else if (b_bit) { 1405fcf5ef2aSThomas Huth LOG_DIS("rtbd ir=%x\n", dc->ir); 1406fcf5ef2aSThomas Huth dc->tb_flags |= DRTB_FLAG; 1407fcf5ef2aSThomas Huth } else if (e_bit) { 1408fcf5ef2aSThomas Huth LOG_DIS("rted ir=%x\n", dc->ir); 1409fcf5ef2aSThomas Huth dc->tb_flags |= DRTE_FLAG; 1410fcf5ef2aSThomas Huth } else 1411fcf5ef2aSThomas Huth LOG_DIS("rts ir=%x\n", dc->ir); 1412fcf5ef2aSThomas Huth 1413fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 14149b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 14150f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 1416fcf5ef2aSThomas Huth } 1417fcf5ef2aSThomas Huth 1418fcf5ef2aSThomas Huth static int dec_check_fpuv2(DisasContext *dc) 1419fcf5ef2aSThomas Huth { 1420fcf5ef2aSThomas Huth if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { 142141ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_FPU); 1422fcf5ef2aSThomas Huth } 14232016a6a7SJoe Komlodi return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; 1424fcf5ef2aSThomas Huth } 1425fcf5ef2aSThomas Huth 1426fcf5ef2aSThomas Huth static void dec_fpu(DisasContext *dc) 1427fcf5ef2aSThomas Huth { 1428fcf5ef2aSThomas Huth unsigned int fpu_insn; 1429fcf5ef2aSThomas Huth 14309ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) { 1431fcf5ef2aSThomas Huth return; 1432fcf5ef2aSThomas Huth } 1433fcf5ef2aSThomas Huth 1434fcf5ef2aSThomas Huth fpu_insn = (dc->ir >> 7) & 7; 1435fcf5ef2aSThomas Huth 1436fcf5ef2aSThomas Huth switch (fpu_insn) { 1437fcf5ef2aSThomas Huth case 0: 1438fcf5ef2aSThomas Huth gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1439fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1440fcf5ef2aSThomas Huth break; 1441fcf5ef2aSThomas Huth 1442fcf5ef2aSThomas Huth case 1: 1443fcf5ef2aSThomas Huth gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1444fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1445fcf5ef2aSThomas Huth break; 1446fcf5ef2aSThomas Huth 1447fcf5ef2aSThomas Huth case 2: 1448fcf5ef2aSThomas Huth gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1449fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1450fcf5ef2aSThomas Huth break; 1451fcf5ef2aSThomas Huth 1452fcf5ef2aSThomas Huth case 3: 1453fcf5ef2aSThomas Huth gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1454fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1455fcf5ef2aSThomas Huth break; 1456fcf5ef2aSThomas Huth 1457fcf5ef2aSThomas Huth case 4: 1458fcf5ef2aSThomas Huth switch ((dc->ir >> 4) & 7) { 1459fcf5ef2aSThomas Huth case 0: 1460fcf5ef2aSThomas Huth gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env, 1461fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1462fcf5ef2aSThomas Huth break; 1463fcf5ef2aSThomas Huth case 1: 1464fcf5ef2aSThomas Huth gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env, 1465fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1466fcf5ef2aSThomas Huth break; 1467fcf5ef2aSThomas Huth case 2: 1468fcf5ef2aSThomas Huth gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env, 1469fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1470fcf5ef2aSThomas Huth break; 1471fcf5ef2aSThomas Huth case 3: 1472fcf5ef2aSThomas Huth gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env, 1473fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1474fcf5ef2aSThomas Huth break; 1475fcf5ef2aSThomas Huth case 4: 1476fcf5ef2aSThomas Huth gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env, 1477fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1478fcf5ef2aSThomas Huth break; 1479fcf5ef2aSThomas Huth case 5: 1480fcf5ef2aSThomas Huth gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env, 1481fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1482fcf5ef2aSThomas Huth break; 1483fcf5ef2aSThomas Huth case 6: 1484fcf5ef2aSThomas Huth gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env, 1485fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1486fcf5ef2aSThomas Huth break; 1487fcf5ef2aSThomas Huth default: 1488fcf5ef2aSThomas Huth qemu_log_mask(LOG_UNIMP, 1489fcf5ef2aSThomas Huth "unimplemented fcmp fpu_insn=%x pc=%x" 1490fcf5ef2aSThomas Huth " opc=%x\n", 1491fcf5ef2aSThomas Huth fpu_insn, dc->pc, dc->opcode); 1492fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1493fcf5ef2aSThomas Huth break; 1494fcf5ef2aSThomas Huth } 1495fcf5ef2aSThomas Huth break; 1496fcf5ef2aSThomas Huth 1497fcf5ef2aSThomas Huth case 5: 1498fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1499fcf5ef2aSThomas Huth return; 1500fcf5ef2aSThomas Huth } 1501fcf5ef2aSThomas Huth gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1502fcf5ef2aSThomas Huth break; 1503fcf5ef2aSThomas Huth 1504fcf5ef2aSThomas Huth case 6: 1505fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1506fcf5ef2aSThomas Huth return; 1507fcf5ef2aSThomas Huth } 1508fcf5ef2aSThomas Huth gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1509fcf5ef2aSThomas Huth break; 1510fcf5ef2aSThomas Huth 1511fcf5ef2aSThomas Huth case 7: 1512fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1513fcf5ef2aSThomas Huth return; 1514fcf5ef2aSThomas Huth } 1515fcf5ef2aSThomas Huth gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1516fcf5ef2aSThomas Huth break; 1517fcf5ef2aSThomas Huth 1518fcf5ef2aSThomas Huth default: 1519fcf5ef2aSThomas Huth qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x" 1520fcf5ef2aSThomas Huth " opc=%x\n", 1521fcf5ef2aSThomas Huth fpu_insn, dc->pc, dc->opcode); 1522fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1523fcf5ef2aSThomas Huth break; 1524fcf5ef2aSThomas Huth } 1525fcf5ef2aSThomas Huth } 1526fcf5ef2aSThomas Huth 1527fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc) 1528fcf5ef2aSThomas Huth { 15299ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 1530fcf5ef2aSThomas Huth return; 1531fcf5ef2aSThomas Huth } 1532fcf5ef2aSThomas Huth qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode); 1533fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1534fcf5ef2aSThomas Huth } 1535fcf5ef2aSThomas Huth 1536fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 1537fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc) 1538fcf5ef2aSThomas Huth { 1539fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1540fcf5ef2aSThomas Huth int ctrl; 1541fcf5ef2aSThomas Huth 1542fcf5ef2aSThomas Huth LOG_DIS("%s%s imm=%x\n", dc->rd ? "get" : "put", 1543fcf5ef2aSThomas Huth dc->type_b ? "" : "d", dc->imm); 1544fcf5ef2aSThomas Huth 1545bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 1546fcf5ef2aSThomas Huth return; 1547fcf5ef2aSThomas Huth } 1548fcf5ef2aSThomas Huth 1549cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 1550fcf5ef2aSThomas Huth if (dc->type_b) { 1551cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 1552fcf5ef2aSThomas Huth ctrl = dc->imm >> 10; 1553fcf5ef2aSThomas Huth } else { 1554cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 1555fcf5ef2aSThomas Huth ctrl = dc->imm >> 5; 1556fcf5ef2aSThomas Huth } 1557fcf5ef2aSThomas Huth 1558cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 1559fcf5ef2aSThomas Huth 1560fcf5ef2aSThomas Huth if (dc->rd == 0) { 1561fcf5ef2aSThomas Huth gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 1562fcf5ef2aSThomas Huth } else { 1563fcf5ef2aSThomas Huth gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 1564fcf5ef2aSThomas Huth } 1565cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1566cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 1567fcf5ef2aSThomas Huth } 1568fcf5ef2aSThomas Huth 1569fcf5ef2aSThomas Huth static struct decoder_info { 1570fcf5ef2aSThomas Huth struct { 1571fcf5ef2aSThomas Huth uint32_t bits; 1572fcf5ef2aSThomas Huth uint32_t mask; 1573fcf5ef2aSThomas Huth }; 1574fcf5ef2aSThomas Huth void (*dec)(DisasContext *dc); 1575fcf5ef2aSThomas Huth } decinfo[] = { 1576fcf5ef2aSThomas Huth {DEC_ADD, dec_add}, 1577fcf5ef2aSThomas Huth {DEC_SUB, dec_sub}, 1578fcf5ef2aSThomas Huth {DEC_AND, dec_and}, 1579fcf5ef2aSThomas Huth {DEC_XOR, dec_xor}, 1580fcf5ef2aSThomas Huth {DEC_OR, dec_or}, 1581fcf5ef2aSThomas Huth {DEC_BIT, dec_bit}, 1582fcf5ef2aSThomas Huth {DEC_BARREL, dec_barrel}, 1583fcf5ef2aSThomas Huth {DEC_LD, dec_load}, 1584fcf5ef2aSThomas Huth {DEC_ST, dec_store}, 1585fcf5ef2aSThomas Huth {DEC_IMM, dec_imm}, 1586fcf5ef2aSThomas Huth {DEC_BR, dec_br}, 1587fcf5ef2aSThomas Huth {DEC_BCC, dec_bcc}, 1588fcf5ef2aSThomas Huth {DEC_RTS, dec_rts}, 1589fcf5ef2aSThomas Huth {DEC_FPU, dec_fpu}, 1590fcf5ef2aSThomas Huth {DEC_MUL, dec_mul}, 1591fcf5ef2aSThomas Huth {DEC_DIV, dec_div}, 1592fcf5ef2aSThomas Huth {DEC_MSR, dec_msr}, 1593fcf5ef2aSThomas Huth {DEC_STREAM, dec_stream}, 1594fcf5ef2aSThomas Huth {{0, 0}, dec_null} 1595fcf5ef2aSThomas Huth }; 1596fcf5ef2aSThomas Huth 1597fcf5ef2aSThomas Huth static inline void decode(DisasContext *dc, uint32_t ir) 1598fcf5ef2aSThomas Huth { 1599fcf5ef2aSThomas Huth int i; 1600fcf5ef2aSThomas Huth 1601fcf5ef2aSThomas Huth dc->ir = ir; 1602fcf5ef2aSThomas Huth LOG_DIS("%8.8x\t", dc->ir); 1603fcf5ef2aSThomas Huth 1604462c2544SEdgar E. Iglesias if (ir == 0) { 16051ee1bd28SEdgar E. Iglesias trap_illegal(dc, dc->cpu->cfg.opcode_0_illegal); 1606462c2544SEdgar E. Iglesias /* Don't decode nop/zero instructions any further. */ 1607462c2544SEdgar E. Iglesias return; 1608462c2544SEdgar E. Iglesias } 1609fcf5ef2aSThomas Huth 1610fcf5ef2aSThomas Huth /* bit 2 seems to indicate insn type. */ 1611fcf5ef2aSThomas Huth dc->type_b = ir & (1 << 29); 1612fcf5ef2aSThomas Huth 1613fcf5ef2aSThomas Huth dc->opcode = EXTRACT_FIELD(ir, 26, 31); 1614fcf5ef2aSThomas Huth dc->rd = EXTRACT_FIELD(ir, 21, 25); 1615fcf5ef2aSThomas Huth dc->ra = EXTRACT_FIELD(ir, 16, 20); 1616fcf5ef2aSThomas Huth dc->rb = EXTRACT_FIELD(ir, 11, 15); 1617fcf5ef2aSThomas Huth dc->imm = EXTRACT_FIELD(ir, 0, 15); 1618fcf5ef2aSThomas Huth 1619fcf5ef2aSThomas Huth /* Large switch for all insns. */ 1620fcf5ef2aSThomas Huth for (i = 0; i < ARRAY_SIZE(decinfo); i++) { 1621fcf5ef2aSThomas Huth if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { 1622fcf5ef2aSThomas Huth decinfo[i].dec(dc); 1623fcf5ef2aSThomas Huth break; 1624fcf5ef2aSThomas Huth } 1625fcf5ef2aSThomas Huth } 1626fcf5ef2aSThomas Huth } 1627fcf5ef2aSThomas Huth 1628fcf5ef2aSThomas Huth /* generate intermediate code for basic block 'tb'. */ 16298b86d6d2SRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) 1630fcf5ef2aSThomas Huth { 16319c489ea6SLluís Vilanova CPUMBState *env = cs->env_ptr; 1632f5c7e93aSRichard Henderson MicroBlazeCPU *cpu = env_archcpu(env); 1633fcf5ef2aSThomas Huth uint32_t pc_start; 1634fcf5ef2aSThomas Huth struct DisasContext ctx; 1635fcf5ef2aSThomas Huth struct DisasContext *dc = &ctx; 163656371527SEmilio G. Cota uint32_t page_start, org_flags; 1637cfeea807SEdgar E. Iglesias uint32_t npc; 1638fcf5ef2aSThomas Huth int num_insns; 1639fcf5ef2aSThomas Huth 1640fcf5ef2aSThomas Huth pc_start = tb->pc; 1641fcf5ef2aSThomas Huth dc->cpu = cpu; 1642fcf5ef2aSThomas Huth dc->tb = tb; 1643fcf5ef2aSThomas Huth org_flags = dc->synced_flags = dc->tb_flags = tb->flags; 1644fcf5ef2aSThomas Huth 1645fcf5ef2aSThomas Huth dc->is_jmp = DISAS_NEXT; 1646fcf5ef2aSThomas Huth dc->jmp = 0; 1647fcf5ef2aSThomas Huth dc->delayed_branch = !!(dc->tb_flags & D_FLAG); 1648fcf5ef2aSThomas Huth if (dc->delayed_branch) { 1649fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 1650fcf5ef2aSThomas Huth } 1651fcf5ef2aSThomas Huth dc->pc = pc_start; 1652fcf5ef2aSThomas Huth dc->singlestep_enabled = cs->singlestep_enabled; 1653fcf5ef2aSThomas Huth dc->cpustate_changed = 0; 1654fcf5ef2aSThomas Huth dc->abort_at_next_insn = 0; 1655fcf5ef2aSThomas Huth 1656fcf5ef2aSThomas Huth if (pc_start & 3) { 1657fcf5ef2aSThomas Huth cpu_abort(cs, "Microblaze: unaligned PC=%x\n", pc_start); 1658fcf5ef2aSThomas Huth } 1659fcf5ef2aSThomas Huth 166056371527SEmilio G. Cota page_start = pc_start & TARGET_PAGE_MASK; 1661fcf5ef2aSThomas Huth num_insns = 0; 1662fcf5ef2aSThomas Huth 1663fcf5ef2aSThomas Huth gen_tb_start(tb); 1664fcf5ef2aSThomas Huth do 1665fcf5ef2aSThomas Huth { 1666fcf5ef2aSThomas Huth tcg_gen_insn_start(dc->pc); 1667fcf5ef2aSThomas Huth num_insns++; 1668fcf5ef2aSThomas Huth 1669fcf5ef2aSThomas Huth if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { 167041ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1671fcf5ef2aSThomas Huth /* The address covered by the breakpoint must be included in 1672fcf5ef2aSThomas Huth [tb->pc, tb->pc + tb->size) in order to for it to be 1673fcf5ef2aSThomas Huth properly cleared -- thus we increment the PC here so that 1674fcf5ef2aSThomas Huth the logic setting tb->size below does the right thing. */ 1675fcf5ef2aSThomas Huth dc->pc += 4; 1676fcf5ef2aSThomas Huth break; 1677fcf5ef2aSThomas Huth } 1678fcf5ef2aSThomas Huth 1679fcf5ef2aSThomas Huth /* Pretty disas. */ 1680fcf5ef2aSThomas Huth LOG_DIS("%8.8x:\t", dc->pc); 1681fcf5ef2aSThomas Huth 1682c5a49c63SEmilio G. Cota if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { 1683fcf5ef2aSThomas Huth gen_io_start(); 1684fcf5ef2aSThomas Huth } 1685fcf5ef2aSThomas Huth 1686fcf5ef2aSThomas Huth dc->clear_imm = 1; 1687fcf5ef2aSThomas Huth decode(dc, cpu_ldl_code(env, dc->pc)); 1688fcf5ef2aSThomas Huth if (dc->clear_imm) 1689fcf5ef2aSThomas Huth dc->tb_flags &= ~IMM_FLAG; 1690fcf5ef2aSThomas Huth dc->pc += 4; 1691fcf5ef2aSThomas Huth 1692fcf5ef2aSThomas Huth if (dc->delayed_branch) { 1693fcf5ef2aSThomas Huth dc->delayed_branch--; 1694fcf5ef2aSThomas Huth if (!dc->delayed_branch) { 1695fcf5ef2aSThomas Huth if (dc->tb_flags & DRTI_FLAG) 1696fcf5ef2aSThomas Huth do_rti(dc); 1697fcf5ef2aSThomas Huth if (dc->tb_flags & DRTB_FLAG) 1698fcf5ef2aSThomas Huth do_rtb(dc); 1699fcf5ef2aSThomas Huth if (dc->tb_flags & DRTE_FLAG) 1700fcf5ef2aSThomas Huth do_rte(dc); 1701fcf5ef2aSThomas Huth /* Clear the delay slot flag. */ 1702fcf5ef2aSThomas Huth dc->tb_flags &= ~D_FLAG; 1703fcf5ef2aSThomas Huth /* If it is a direct jump, try direct chaining. */ 1704fcf5ef2aSThomas Huth if (dc->jmp == JMP_INDIRECT) { 17050f96e96bSRichard Henderson TCGv_i32 tmp_pc = tcg_const_i32(dc->pc); 17060f96e96bSRichard Henderson eval_cond_jmp(dc, cpu_btarget, tmp_pc); 17070f96e96bSRichard Henderson tcg_temp_free_i32(tmp_pc); 1708fcf5ef2aSThomas Huth dc->is_jmp = DISAS_JUMP; 1709fcf5ef2aSThomas Huth } else if (dc->jmp == JMP_DIRECT) { 1710fcf5ef2aSThomas Huth t_sync_flags(dc); 1711fcf5ef2aSThomas Huth gen_goto_tb(dc, 0, dc->jmp_pc); 1712fcf5ef2aSThomas Huth dc->is_jmp = DISAS_TB_JUMP; 1713fcf5ef2aSThomas Huth } else if (dc->jmp == JMP_DIRECT_CC) { 1714fcf5ef2aSThomas Huth TCGLabel *l1 = gen_new_label(); 1715fcf5ef2aSThomas Huth t_sync_flags(dc); 1716fcf5ef2aSThomas Huth /* Conditional jmp. */ 17179b158558SRichard Henderson tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); 1718fcf5ef2aSThomas Huth gen_goto_tb(dc, 1, dc->pc); 1719fcf5ef2aSThomas Huth gen_set_label(l1); 1720fcf5ef2aSThomas Huth gen_goto_tb(dc, 0, dc->jmp_pc); 1721fcf5ef2aSThomas Huth 1722fcf5ef2aSThomas Huth dc->is_jmp = DISAS_TB_JUMP; 1723fcf5ef2aSThomas Huth } 1724fcf5ef2aSThomas Huth break; 1725fcf5ef2aSThomas Huth } 1726fcf5ef2aSThomas Huth } 1727fcf5ef2aSThomas Huth if (cs->singlestep_enabled) { 1728fcf5ef2aSThomas Huth break; 1729fcf5ef2aSThomas Huth } 1730fcf5ef2aSThomas Huth } while (!dc->is_jmp && !dc->cpustate_changed 1731fcf5ef2aSThomas Huth && !tcg_op_buf_full() 1732fcf5ef2aSThomas Huth && !singlestep 173356371527SEmilio G. Cota && (dc->pc - page_start < TARGET_PAGE_SIZE) 1734fcf5ef2aSThomas Huth && num_insns < max_insns); 1735fcf5ef2aSThomas Huth 1736fcf5ef2aSThomas Huth npc = dc->pc; 1737fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 1738fcf5ef2aSThomas Huth if (dc->tb_flags & D_FLAG) { 1739fcf5ef2aSThomas Huth dc->is_jmp = DISAS_UPDATE; 17400f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, npc); 1741fcf5ef2aSThomas Huth sync_jmpstate(dc); 1742fcf5ef2aSThomas Huth } else 1743fcf5ef2aSThomas Huth npc = dc->jmp_pc; 1744fcf5ef2aSThomas Huth } 1745fcf5ef2aSThomas Huth 1746fcf5ef2aSThomas Huth /* Force an update if the per-tb cpu state has changed. */ 1747fcf5ef2aSThomas Huth if (dc->is_jmp == DISAS_NEXT 1748fcf5ef2aSThomas Huth && (dc->cpustate_changed || org_flags != dc->tb_flags)) { 1749fcf5ef2aSThomas Huth dc->is_jmp = DISAS_UPDATE; 17500f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, npc); 1751fcf5ef2aSThomas Huth } 1752fcf5ef2aSThomas Huth t_sync_flags(dc); 1753fcf5ef2aSThomas Huth 1754fcf5ef2aSThomas Huth if (unlikely(cs->singlestep_enabled)) { 1755fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1756fcf5ef2aSThomas Huth 1757fcf5ef2aSThomas Huth if (dc->is_jmp != DISAS_JUMP) { 17580f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, npc); 1759fcf5ef2aSThomas Huth } 1760fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 1761fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 1762fcf5ef2aSThomas Huth } else { 1763fcf5ef2aSThomas Huth switch(dc->is_jmp) { 1764fcf5ef2aSThomas Huth case DISAS_NEXT: 1765fcf5ef2aSThomas Huth gen_goto_tb(dc, 1, npc); 1766fcf5ef2aSThomas Huth break; 1767fcf5ef2aSThomas Huth default: 1768fcf5ef2aSThomas Huth case DISAS_JUMP: 1769fcf5ef2aSThomas Huth case DISAS_UPDATE: 1770fcf5ef2aSThomas Huth /* indicate that the hash table must be used 1771fcf5ef2aSThomas Huth to find the next TB */ 177207ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1773fcf5ef2aSThomas Huth break; 1774fcf5ef2aSThomas Huth case DISAS_TB_JUMP: 1775fcf5ef2aSThomas Huth /* nothing more to generate */ 1776fcf5ef2aSThomas Huth break; 1777fcf5ef2aSThomas Huth } 1778fcf5ef2aSThomas Huth } 1779fcf5ef2aSThomas Huth gen_tb_end(tb, num_insns); 1780fcf5ef2aSThomas Huth 1781fcf5ef2aSThomas Huth tb->size = dc->pc - pc_start; 1782fcf5ef2aSThomas Huth tb->icount = num_insns; 1783fcf5ef2aSThomas Huth 1784fcf5ef2aSThomas Huth #ifdef DEBUG_DISAS 1785fcf5ef2aSThomas Huth #if !SIM_COMPAT 1786fcf5ef2aSThomas Huth if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) 1787fcf5ef2aSThomas Huth && qemu_log_in_addr_range(pc_start)) { 1788fc59d2d8SRobert Foley FILE *logfile = qemu_log_lock(); 1789fcf5ef2aSThomas Huth qemu_log("--------------\n"); 17901d48474dSRichard Henderson log_target_disas(cs, pc_start, dc->pc - pc_start); 1791fc59d2d8SRobert Foley qemu_log_unlock(logfile); 1792fcf5ef2aSThomas Huth } 1793fcf5ef2aSThomas Huth #endif 1794fcf5ef2aSThomas Huth #endif 1795fcf5ef2aSThomas Huth assert(!dc->abort_at_next_insn); 1796fcf5ef2aSThomas Huth } 1797fcf5ef2aSThomas Huth 179890c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1799fcf5ef2aSThomas Huth { 1800fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1801fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 1802fcf5ef2aSThomas Huth int i; 1803fcf5ef2aSThomas Huth 180490c84c56SMarkus Armbruster if (!env) { 1805fcf5ef2aSThomas Huth return; 180690c84c56SMarkus Armbruster } 1807fcf5ef2aSThomas Huth 18080f96e96bSRichard Henderson qemu_fprintf(f, "IN: PC=%x %s\n", 180976e8187dSRichard Henderson env->pc, lookup_symbol(env->pc)); 18106efd5599SRichard Henderson qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " 1811eb2022b7SRichard Henderson "imm=%x iflags=%x fsr=%x rbtr=%x\n", 181278e9caf2SRichard Henderson env->msr, env->esr, env->ear, 1813eb2022b7SRichard Henderson env->imm, env->iflags, env->fsr, env->btr); 18140f96e96bSRichard Henderson qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 1815fcf5ef2aSThomas Huth env->btaken, env->btarget, 18162e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18172e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18182e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18192e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18202ead1b18SJoe Komlodi for (i = 0; i < 12; i++) { 18212ead1b18SJoe Komlodi qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); 18222ead1b18SJoe Komlodi if ((i + 1) % 4 == 0) { 18232ead1b18SJoe Komlodi qemu_fprintf(f, "\n"); 18242ead1b18SJoe Komlodi } 18252ead1b18SJoe Komlodi } 1826fcf5ef2aSThomas Huth 18272ead1b18SJoe Komlodi /* Registers that aren't modeled are reported as 0 */ 182839db007eSRichard Henderson qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " 1829af20a93aSRichard Henderson "rtlblo=0 rtlbhi=0\n", env->edr); 18302ead1b18SJoe Komlodi qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); 1831fcf5ef2aSThomas Huth for (i = 0; i < 32; i++) { 183290c84c56SMarkus Armbruster qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); 1833fcf5ef2aSThomas Huth if ((i + 1) % 4 == 0) 183490c84c56SMarkus Armbruster qemu_fprintf(f, "\n"); 1835fcf5ef2aSThomas Huth } 183690c84c56SMarkus Armbruster qemu_fprintf(f, "\n\n"); 1837fcf5ef2aSThomas Huth } 1838fcf5ef2aSThomas Huth 1839fcf5ef2aSThomas Huth void mb_tcg_init(void) 1840fcf5ef2aSThomas Huth { 1841*480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1842*480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1843fcf5ef2aSThomas Huth 1844*480d29a8SRichard Henderson static const struct { 1845*480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1846*480d29a8SRichard Henderson } i32s[] = { 1847*480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1848*480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1849*480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1850*480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1851*480d29a8SRichard Henderson 1852*480d29a8SRichard Henderson SP(pc), 1853*480d29a8SRichard Henderson SP(msr), 1854*480d29a8SRichard Henderson SP(imm), 1855*480d29a8SRichard Henderson SP(iflags), 1856*480d29a8SRichard Henderson SP(btaken), 1857*480d29a8SRichard Henderson SP(btarget), 1858*480d29a8SRichard Henderson SP(res_val), 1859*480d29a8SRichard Henderson }; 1860*480d29a8SRichard Henderson 1861*480d29a8SRichard Henderson #undef R 1862*480d29a8SRichard Henderson #undef SP 1863*480d29a8SRichard Henderson 1864*480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1865*480d29a8SRichard Henderson *i32s[i].var = 1866*480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1867fcf5ef2aSThomas Huth } 186876e8187dSRichard Henderson 1869*480d29a8SRichard Henderson cpu_res_addr = 1870*480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1871fcf5ef2aSThomas Huth } 1872fcf5ef2aSThomas Huth 1873fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1874fcf5ef2aSThomas Huth target_ulong *data) 1875fcf5ef2aSThomas Huth { 187676e8187dSRichard Henderson env->pc = data[0]; 1877fcf5ef2aSThomas Huth } 1878