1fcf5ef2aSThomas Huth /* 2fcf5ef2aSThomas Huth * Xilinx MicroBlaze emulation for qemu: main translation routines. 3fcf5ef2aSThomas Huth * 4fcf5ef2aSThomas Huth * Copyright (c) 2009 Edgar E. Iglesias. 5fcf5ef2aSThomas Huth * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. 6fcf5ef2aSThomas Huth * 7fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or 8fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public 9fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either 10fcf5ef2aSThomas Huth * version 2 of the License, or (at your option) any later version. 11fcf5ef2aSThomas Huth * 12fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 13fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fcf5ef2aSThomas Huth * Lesser General Public License for more details. 16fcf5ef2aSThomas Huth * 17fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 18fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fcf5ef2aSThomas Huth */ 20fcf5ef2aSThomas Huth 21fcf5ef2aSThomas Huth #include "qemu/osdep.h" 22fcf5ef2aSThomas Huth #include "cpu.h" 23fcf5ef2aSThomas Huth #include "disas/disas.h" 24fcf5ef2aSThomas Huth #include "exec/exec-all.h" 25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h" 26fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 27fcf5ef2aSThomas Huth #include "microblaze-decode.h" 28fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h" 29fcf5ef2aSThomas Huth #include "exec/helper-gen.h" 3077fc6f5eSLluís Vilanova #include "exec/translator.h" 3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h" 32fcf5ef2aSThomas Huth 33fcf5ef2aSThomas Huth #include "trace-tcg.h" 34fcf5ef2aSThomas Huth #include "exec/log.h" 35fcf5ef2aSThomas Huth 36fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \ 37fcf5ef2aSThomas Huth (((src) >> start) & ((1 << (end - start + 1)) - 1)) 38fcf5ef2aSThomas Huth 3977fc6f5eSLluís Vilanova /* is_jmp field values */ 4077fc6f5eSLluís Vilanova #define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ 4177fc6f5eSLluís Vilanova #define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ 4277fc6f5eSLluís Vilanova 43cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32]; 440f96e96bSRichard Henderson static TCGv_i32 cpu_pc; 453e0e16aeSRichard Henderson static TCGv_i32 cpu_msr; 461074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c; 479b158558SRichard Henderson static TCGv_i32 cpu_imm; 489b158558SRichard Henderson static TCGv_i32 cpu_btaken; 490f96e96bSRichard Henderson static TCGv_i32 cpu_btarget; 509b158558SRichard Henderson static TCGv_i32 cpu_iflags; 519b158558SRichard Henderson static TCGv cpu_res_addr; 529b158558SRichard Henderson static TCGv_i32 cpu_res_val; 53fcf5ef2aSThomas Huth 54fcf5ef2aSThomas Huth #include "exec/gen-icount.h" 55fcf5ef2aSThomas Huth 56fcf5ef2aSThomas Huth /* This is the state at translation time. */ 57fcf5ef2aSThomas Huth typedef struct DisasContext { 58d4705ae0SRichard Henderson DisasContextBase base; 59fcf5ef2aSThomas Huth MicroBlazeCPU *cpu; 60fcf5ef2aSThomas Huth 61*20800179SRichard Henderson TCGv_i32 r0; 62*20800179SRichard Henderson bool r0_set; 63*20800179SRichard Henderson 64fcf5ef2aSThomas Huth /* Decoder. */ 65fcf5ef2aSThomas Huth int type_b; 66fcf5ef2aSThomas Huth uint32_t ir; 67d7ecb757SRichard Henderson uint32_t ext_imm; 68fcf5ef2aSThomas Huth uint8_t opcode; 69fcf5ef2aSThomas Huth uint8_t rd, ra, rb; 70fcf5ef2aSThomas Huth uint16_t imm; 71fcf5ef2aSThomas Huth 72fcf5ef2aSThomas Huth unsigned int cpustate_changed; 73fcf5ef2aSThomas Huth unsigned int delayed_branch; 74fcf5ef2aSThomas Huth unsigned int tb_flags, synced_flags; /* tb dependent flags. */ 75fcf5ef2aSThomas Huth unsigned int clear_imm; 76fcf5ef2aSThomas Huth 77fcf5ef2aSThomas Huth #define JMP_NOJMP 0 78fcf5ef2aSThomas Huth #define JMP_DIRECT 1 79fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2 80fcf5ef2aSThomas Huth #define JMP_INDIRECT 3 81fcf5ef2aSThomas Huth unsigned int jmp; 82fcf5ef2aSThomas Huth uint32_t jmp_pc; 83fcf5ef2aSThomas Huth 84fcf5ef2aSThomas Huth int abort_at_next_insn; 85fcf5ef2aSThomas Huth } DisasContext; 86fcf5ef2aSThomas Huth 87*20800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x) 88*20800179SRichard Henderson { 89*20800179SRichard Henderson if (dc->tb_flags & IMM_FLAG) { 90*20800179SRichard Henderson return deposit32(dc->ext_imm, 0, 16, x); 91*20800179SRichard Henderson } 92*20800179SRichard Henderson return x; 93*20800179SRichard Henderson } 94*20800179SRichard Henderson 9544d1432bSRichard Henderson /* Include the auto-generated decoder. */ 9644d1432bSRichard Henderson #include "decode-insns.c.inc" 9744d1432bSRichard Henderson 98fcf5ef2aSThomas Huth static inline void t_sync_flags(DisasContext *dc) 99fcf5ef2aSThomas Huth { 100fcf5ef2aSThomas Huth /* Synch the tb dependent flags between translator and runtime. */ 101fcf5ef2aSThomas Huth if (dc->tb_flags != dc->synced_flags) { 1029b158558SRichard Henderson tcg_gen_movi_i32(cpu_iflags, dc->tb_flags); 103fcf5ef2aSThomas Huth dc->synced_flags = dc->tb_flags; 104fcf5ef2aSThomas Huth } 105fcf5ef2aSThomas Huth } 106fcf5ef2aSThomas Huth 10741ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index) 108fcf5ef2aSThomas Huth { 109fcf5ef2aSThomas Huth TCGv_i32 tmp = tcg_const_i32(index); 110fcf5ef2aSThomas Huth 111fcf5ef2aSThomas Huth gen_helper_raise_exception(cpu_env, tmp); 112fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp); 113d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 114fcf5ef2aSThomas Huth } 115fcf5ef2aSThomas Huth 11641ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index) 11741ba37c4SRichard Henderson { 11841ba37c4SRichard Henderson t_sync_flags(dc); 119d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 12041ba37c4SRichard Henderson gen_raise_exception(dc, index); 12141ba37c4SRichard Henderson } 12241ba37c4SRichard Henderson 12341ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec) 12441ba37c4SRichard Henderson { 12541ba37c4SRichard Henderson TCGv_i32 tmp = tcg_const_i32(esr_ec); 12641ba37c4SRichard Henderson tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr)); 12741ba37c4SRichard Henderson tcg_temp_free_i32(tmp); 12841ba37c4SRichard Henderson 12941ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_HW_EXCP); 13041ba37c4SRichard Henderson } 13141ba37c4SRichard Henderson 132fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) 133fcf5ef2aSThomas Huth { 134fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY 135d4705ae0SRichard Henderson return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); 136fcf5ef2aSThomas Huth #else 137fcf5ef2aSThomas Huth return true; 138fcf5ef2aSThomas Huth #endif 139fcf5ef2aSThomas Huth } 140fcf5ef2aSThomas Huth 141fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) 142fcf5ef2aSThomas Huth { 143d4705ae0SRichard Henderson if (dc->base.singlestep_enabled) { 1440b46fa08SRichard Henderson TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); 1450b46fa08SRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 1460b46fa08SRichard Henderson gen_helper_raise_exception(cpu_env, tmp); 1470b46fa08SRichard Henderson tcg_temp_free_i32(tmp); 1480b46fa08SRichard Henderson } else if (use_goto_tb(dc, dest)) { 149fcf5ef2aSThomas Huth tcg_gen_goto_tb(n); 1500f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 151d4705ae0SRichard Henderson tcg_gen_exit_tb(dc->base.tb, n); 152fcf5ef2aSThomas Huth } else { 1530f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_pc, dest); 15407ea28b4SRichard Henderson tcg_gen_exit_tb(NULL, 0); 155fcf5ef2aSThomas Huth } 156d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_NORETURN; 157fcf5ef2aSThomas Huth } 158fcf5ef2aSThomas Huth 159bdfc1e88SEdgar E. Iglesias /* 1609ba8cd45SEdgar E. Iglesias * Returns true if the insn an illegal operation. 1619ba8cd45SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 1629ba8cd45SEdgar E. Iglesias */ 1639ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond) 1649ba8cd45SEdgar E. Iglesias { 1659ba8cd45SEdgar E. Iglesias if (cond && (dc->tb_flags & MSR_EE_FLAG) 1665143fdf3SEdgar E. Iglesias && dc->cpu->cfg.illegal_opcode_exception) { 16741ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP); 1689ba8cd45SEdgar E. Iglesias } 1699ba8cd45SEdgar E. Iglesias return cond; 1709ba8cd45SEdgar E. Iglesias } 1719ba8cd45SEdgar E. Iglesias 1729ba8cd45SEdgar E. Iglesias /* 173bdfc1e88SEdgar E. Iglesias * Returns true if the insn is illegal in userspace. 174bdfc1e88SEdgar E. Iglesias * If exceptions are enabled, an exception is raised. 175bdfc1e88SEdgar E. Iglesias */ 176bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond) 177bdfc1e88SEdgar E. Iglesias { 178bdfc1e88SEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 179bdfc1e88SEdgar E. Iglesias bool cond_user = cond && mem_index == MMU_USER_IDX; 180bdfc1e88SEdgar E. Iglesias 181bdfc1e88SEdgar E. Iglesias if (cond_user && (dc->tb_flags & MSR_EE_FLAG)) { 18241ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_PRIVINSN); 183bdfc1e88SEdgar E. Iglesias } 184bdfc1e88SEdgar E. Iglesias return cond_user; 185bdfc1e88SEdgar E. Iglesias } 186bdfc1e88SEdgar E. Iglesias 187d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc) 188fcf5ef2aSThomas Huth { 189d7ecb757SRichard Henderson tcg_debug_assert(dc->type_b); 190*20800179SRichard Henderson return typeb_imm(dc, (int16_t)dc->imm); 191fcf5ef2aSThomas Huth } 192fcf5ef2aSThomas Huth 193cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc) 194fcf5ef2aSThomas Huth { 195fcf5ef2aSThomas Huth if (dc->type_b) { 196d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc)); 1979b158558SRichard Henderson return &cpu_imm; 198d7ecb757SRichard Henderson } 199fcf5ef2aSThomas Huth return &cpu_R[dc->rb]; 200fcf5ef2aSThomas Huth } 201fcf5ef2aSThomas Huth 202*20800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg) 203fcf5ef2aSThomas Huth { 204*20800179SRichard Henderson if (likely(reg != 0)) { 205*20800179SRichard Henderson return cpu_R[reg]; 206fcf5ef2aSThomas Huth } 207*20800179SRichard Henderson if (!dc->r0_set) { 208*20800179SRichard Henderson if (dc->r0 == NULL) { 209*20800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 210fcf5ef2aSThomas Huth } 211*20800179SRichard Henderson tcg_gen_movi_i32(dc->r0, 0); 212*20800179SRichard Henderson dc->r0_set = true; 213*20800179SRichard Henderson } 214*20800179SRichard Henderson return dc->r0; 215fcf5ef2aSThomas Huth } 216fcf5ef2aSThomas Huth 217*20800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg) 218*20800179SRichard Henderson { 219*20800179SRichard Henderson if (likely(reg != 0)) { 220*20800179SRichard Henderson return cpu_R[reg]; 221*20800179SRichard Henderson } 222*20800179SRichard Henderson if (dc->r0 == NULL) { 223*20800179SRichard Henderson dc->r0 = tcg_temp_new_i32(); 224*20800179SRichard Henderson } 225*20800179SRichard Henderson return dc->r0; 226fcf5ef2aSThomas Huth } 227fcf5ef2aSThomas Huth 228*20800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, 229*20800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 230*20800179SRichard Henderson { 231*20800179SRichard Henderson TCGv_i32 rd, ra, rb; 232*20800179SRichard Henderson 233*20800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 234*20800179SRichard Henderson return true; 235fcf5ef2aSThomas Huth } 236*20800179SRichard Henderson 237*20800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 238*20800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 239*20800179SRichard Henderson rb = reg_for_read(dc, arg->rb); 240*20800179SRichard Henderson fn(rd, ra, rb); 241*20800179SRichard Henderson return true; 242*20800179SRichard Henderson } 243*20800179SRichard Henderson 244*20800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects, 245*20800179SRichard Henderson void (*fni)(TCGv_i32, TCGv_i32, int32_t)) 246*20800179SRichard Henderson { 247*20800179SRichard Henderson TCGv_i32 rd, ra; 248*20800179SRichard Henderson 249*20800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 250*20800179SRichard Henderson return true; 251*20800179SRichard Henderson } 252*20800179SRichard Henderson 253*20800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 254*20800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 255*20800179SRichard Henderson fni(rd, ra, arg->imm); 256*20800179SRichard Henderson return true; 257*20800179SRichard Henderson } 258*20800179SRichard Henderson 259*20800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects, 260*20800179SRichard Henderson void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32)) 261*20800179SRichard Henderson { 262*20800179SRichard Henderson TCGv_i32 rd, ra, imm; 263*20800179SRichard Henderson 264*20800179SRichard Henderson if (arg->rd == 0 && !side_effects) { 265*20800179SRichard Henderson return true; 266*20800179SRichard Henderson } 267*20800179SRichard Henderson 268*20800179SRichard Henderson rd = reg_for_write(dc, arg->rd); 269*20800179SRichard Henderson ra = reg_for_read(dc, arg->ra); 270*20800179SRichard Henderson imm = tcg_const_i32(arg->imm); 271*20800179SRichard Henderson 272*20800179SRichard Henderson fn(rd, ra, imm); 273*20800179SRichard Henderson 274*20800179SRichard Henderson tcg_temp_free_i32(imm); 275*20800179SRichard Henderson return true; 276*20800179SRichard Henderson } 277*20800179SRichard Henderson 278*20800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \ 279*20800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typea *a) \ 280*20800179SRichard Henderson { return do_typea(dc, a, SE, FN); } 281*20800179SRichard Henderson 282*20800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \ 283*20800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 284*20800179SRichard Henderson { return do_typeb_imm(dc, a, SE, FNI); } 285*20800179SRichard Henderson 286*20800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \ 287*20800179SRichard Henderson static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \ 288*20800179SRichard Henderson { return do_typeb_val(dc, a, SE, FN); } 289*20800179SRichard Henderson 290*20800179SRichard Henderson /* No input carry, but output carry. */ 291*20800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 292*20800179SRichard Henderson { 293*20800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 294*20800179SRichard Henderson 295*20800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero); 296*20800179SRichard Henderson 297*20800179SRichard Henderson tcg_temp_free_i32(zero); 298*20800179SRichard Henderson } 299*20800179SRichard Henderson 300*20800179SRichard Henderson /* Input and output carry. */ 301*20800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 302*20800179SRichard Henderson { 303*20800179SRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 304*20800179SRichard Henderson TCGv_i32 tmp = tcg_temp_new_i32(); 305*20800179SRichard Henderson 306*20800179SRichard Henderson tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); 307*20800179SRichard Henderson tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); 308*20800179SRichard Henderson 309*20800179SRichard Henderson tcg_temp_free_i32(tmp); 310*20800179SRichard Henderson tcg_temp_free_i32(zero); 311*20800179SRichard Henderson } 312*20800179SRichard Henderson 313*20800179SRichard Henderson /* Input carry, but no output carry. */ 314*20800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) 315*20800179SRichard Henderson { 316*20800179SRichard Henderson tcg_gen_add_i32(out, ina, inb); 317*20800179SRichard Henderson tcg_gen_add_i32(out, out, cpu_msr_c); 318*20800179SRichard Henderson } 319*20800179SRichard Henderson 320*20800179SRichard Henderson DO_TYPEA(add, true, gen_add) 321*20800179SRichard Henderson DO_TYPEA(addc, true, gen_addc) 322*20800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32) 323*20800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc) 324*20800179SRichard Henderson 325*20800179SRichard Henderson DO_TYPEBV(addi, true, gen_add) 326*20800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc) 327*20800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32) 328*20800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc) 329*20800179SRichard Henderson 330*20800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg) 331*20800179SRichard Henderson { 332*20800179SRichard Henderson /* If opcode_0_illegal, trap. */ 333*20800179SRichard Henderson if (dc->cpu->cfg.opcode_0_illegal) { 334*20800179SRichard Henderson trap_illegal(dc, true); 335*20800179SRichard Henderson return true; 336*20800179SRichard Henderson } 337*20800179SRichard Henderson /* 338*20800179SRichard Henderson * Otherwise, this is "add r0, r0, r0". 339*20800179SRichard Henderson * Continue to trans_add so that MSR[C] gets cleared. 340*20800179SRichard Henderson */ 341*20800179SRichard Henderson return false; 342fcf5ef2aSThomas Huth } 343fcf5ef2aSThomas Huth 344fcf5ef2aSThomas Huth static void dec_sub(DisasContext *dc) 345fcf5ef2aSThomas Huth { 346fcf5ef2aSThomas Huth unsigned int u, cmp, k, c; 347cfeea807SEdgar E. Iglesias TCGv_i32 cf, na; 348fcf5ef2aSThomas Huth 349fcf5ef2aSThomas Huth u = dc->imm & 2; 350fcf5ef2aSThomas Huth k = dc->opcode & 4; 351fcf5ef2aSThomas Huth c = dc->opcode & 2; 352fcf5ef2aSThomas Huth cmp = (dc->imm & 1) && (!dc->type_b) && k; 353fcf5ef2aSThomas Huth 354fcf5ef2aSThomas Huth if (cmp) { 355fcf5ef2aSThomas Huth if (dc->rd) { 356fcf5ef2aSThomas Huth if (u) 357fcf5ef2aSThomas Huth gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 358fcf5ef2aSThomas Huth else 359fcf5ef2aSThomas Huth gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 360fcf5ef2aSThomas Huth } 361fcf5ef2aSThomas Huth return; 362fcf5ef2aSThomas Huth } 363fcf5ef2aSThomas Huth 364fcf5ef2aSThomas Huth /* Take care of the easy cases first. */ 365fcf5ef2aSThomas Huth if (k) { 366fcf5ef2aSThomas Huth /* k - keep carry, no need to update MSR. */ 367fcf5ef2aSThomas Huth /* If rd == r0, it's a nop. */ 368fcf5ef2aSThomas Huth if (dc->rd) { 369cfeea807SEdgar E. Iglesias tcg_gen_sub_i32(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); 370fcf5ef2aSThomas Huth 371fcf5ef2aSThomas Huth if (c) { 372fcf5ef2aSThomas Huth /* c - Add carry into the result. */ 3731074c0fbSRichard Henderson tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_msr_c); 374fcf5ef2aSThomas Huth } 375fcf5ef2aSThomas Huth } 376fcf5ef2aSThomas Huth return; 377fcf5ef2aSThomas Huth } 378fcf5ef2aSThomas Huth 379fcf5ef2aSThomas Huth /* From now on, we can assume k is zero. So we need to update MSR. */ 380fcf5ef2aSThomas Huth /* Extract carry. And complement a into na. */ 381cfeea807SEdgar E. Iglesias cf = tcg_temp_new_i32(); 382cfeea807SEdgar E. Iglesias na = tcg_temp_new_i32(); 383fcf5ef2aSThomas Huth if (c) { 3841074c0fbSRichard Henderson tcg_gen_mov_i32(cf, cpu_msr_c); 385fcf5ef2aSThomas Huth } else { 386cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cf, 1); 387fcf5ef2aSThomas Huth } 388fcf5ef2aSThomas Huth 389fcf5ef2aSThomas Huth /* d = b + ~a + c. carry defaults to 1. */ 390cfeea807SEdgar E. Iglesias tcg_gen_not_i32(na, cpu_R[dc->ra]); 391fcf5ef2aSThomas Huth 3921074c0fbSRichard Henderson gen_helper_carry(cpu_msr_c, na, *(dec_alu_op_b(dc)), cf); 393fcf5ef2aSThomas Huth if (dc->rd) { 394cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], na, *(dec_alu_op_b(dc))); 395cfeea807SEdgar E. Iglesias tcg_gen_add_i32(cpu_R[dc->rd], cpu_R[dc->rd], cf); 396fcf5ef2aSThomas Huth } 397cfeea807SEdgar E. Iglesias tcg_temp_free_i32(cf); 398cfeea807SEdgar E. Iglesias tcg_temp_free_i32(na); 399fcf5ef2aSThomas Huth } 400fcf5ef2aSThomas Huth 401fcf5ef2aSThomas Huth static void dec_pattern(DisasContext *dc) 402fcf5ef2aSThomas Huth { 403fcf5ef2aSThomas Huth unsigned int mode; 404fcf5ef2aSThomas Huth 4059ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { 4069ba8cd45SEdgar E. Iglesias return; 407fcf5ef2aSThomas Huth } 408fcf5ef2aSThomas Huth 409fcf5ef2aSThomas Huth mode = dc->opcode & 3; 410fcf5ef2aSThomas Huth switch (mode) { 411fcf5ef2aSThomas Huth case 0: 412fcf5ef2aSThomas Huth /* pcmpbf. */ 413fcf5ef2aSThomas Huth if (dc->rd) 414fcf5ef2aSThomas Huth gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 415fcf5ef2aSThomas Huth break; 416fcf5ef2aSThomas Huth case 2: 417fcf5ef2aSThomas Huth if (dc->rd) { 418cfeea807SEdgar E. Iglesias tcg_gen_setcond_i32(TCG_COND_EQ, cpu_R[dc->rd], 419fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 420fcf5ef2aSThomas Huth } 421fcf5ef2aSThomas Huth break; 422fcf5ef2aSThomas Huth case 3: 423fcf5ef2aSThomas Huth if (dc->rd) { 424cfeea807SEdgar E. Iglesias tcg_gen_setcond_i32(TCG_COND_NE, cpu_R[dc->rd], 425fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 426fcf5ef2aSThomas Huth } 427fcf5ef2aSThomas Huth break; 428fcf5ef2aSThomas Huth default: 429fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), 430fcf5ef2aSThomas Huth "unsupported pattern insn opcode=%x\n", dc->opcode); 431fcf5ef2aSThomas Huth break; 432fcf5ef2aSThomas Huth } 433fcf5ef2aSThomas Huth } 434fcf5ef2aSThomas Huth 435fcf5ef2aSThomas Huth static void dec_and(DisasContext *dc) 436fcf5ef2aSThomas Huth { 437fcf5ef2aSThomas Huth unsigned int not; 438fcf5ef2aSThomas Huth 439fcf5ef2aSThomas Huth if (!dc->type_b && (dc->imm & (1 << 10))) { 440fcf5ef2aSThomas Huth dec_pattern(dc); 441fcf5ef2aSThomas Huth return; 442fcf5ef2aSThomas Huth } 443fcf5ef2aSThomas Huth 444fcf5ef2aSThomas Huth not = dc->opcode & (1 << 1); 445fcf5ef2aSThomas Huth 446fcf5ef2aSThomas Huth if (!dc->rd) 447fcf5ef2aSThomas Huth return; 448fcf5ef2aSThomas Huth 449fcf5ef2aSThomas Huth if (not) { 450cfeea807SEdgar E. Iglesias tcg_gen_andc_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 451fcf5ef2aSThomas Huth } else 452cfeea807SEdgar E. Iglesias tcg_gen_and_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 453fcf5ef2aSThomas Huth } 454fcf5ef2aSThomas Huth 455fcf5ef2aSThomas Huth static void dec_or(DisasContext *dc) 456fcf5ef2aSThomas Huth { 457fcf5ef2aSThomas Huth if (!dc->type_b && (dc->imm & (1 << 10))) { 458fcf5ef2aSThomas Huth dec_pattern(dc); 459fcf5ef2aSThomas Huth return; 460fcf5ef2aSThomas Huth } 461fcf5ef2aSThomas Huth 462fcf5ef2aSThomas Huth if (dc->rd) 463cfeea807SEdgar E. Iglesias tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 464fcf5ef2aSThomas Huth } 465fcf5ef2aSThomas Huth 466fcf5ef2aSThomas Huth static void dec_xor(DisasContext *dc) 467fcf5ef2aSThomas Huth { 468fcf5ef2aSThomas Huth if (!dc->type_b && (dc->imm & (1 << 10))) { 469fcf5ef2aSThomas Huth dec_pattern(dc); 470fcf5ef2aSThomas Huth return; 471fcf5ef2aSThomas Huth } 472fcf5ef2aSThomas Huth 473fcf5ef2aSThomas Huth if (dc->rd) 474cfeea807SEdgar E. Iglesias tcg_gen_xor_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 475fcf5ef2aSThomas Huth } 476fcf5ef2aSThomas Huth 4771074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d) 478fcf5ef2aSThomas Huth { 4791074c0fbSRichard Henderson TCGv_i32 t; 4801074c0fbSRichard Henderson 4811074c0fbSRichard Henderson /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */ 4821074c0fbSRichard Henderson t = tcg_temp_new_i32(); 4831074c0fbSRichard Henderson tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC); 4841074c0fbSRichard Henderson tcg_gen_or_i32(d, cpu_msr, t); 4851074c0fbSRichard Henderson tcg_temp_free_i32(t); 486fcf5ef2aSThomas Huth } 487fcf5ef2aSThomas Huth 4881074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v) 489fcf5ef2aSThomas Huth { 490fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 4911074c0fbSRichard Henderson 4921074c0fbSRichard Henderson /* Install MSR_C. */ 4931074c0fbSRichard Henderson tcg_gen_extract_i32(cpu_msr_c, v, 2, 1); 4941074c0fbSRichard Henderson 4951074c0fbSRichard Henderson /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */ 4961074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR)); 497fcf5ef2aSThomas Huth } 498fcf5ef2aSThomas Huth 499fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc) 500fcf5ef2aSThomas Huth { 501fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 502cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 5032023e9a3SEdgar E. Iglesias unsigned int sr, rn; 504f0f7e7f7SEdgar E. Iglesias bool to, clrset, extended = false; 505fcf5ef2aSThomas Huth 5062023e9a3SEdgar E. Iglesias sr = extract32(dc->imm, 0, 14); 5072023e9a3SEdgar E. Iglesias to = extract32(dc->imm, 14, 1); 5082023e9a3SEdgar E. Iglesias clrset = extract32(dc->imm, 15, 1) == 0; 509fcf5ef2aSThomas Huth dc->type_b = 1; 5102023e9a3SEdgar E. Iglesias if (to) { 511fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 512f0f7e7f7SEdgar E. Iglesias } 513f0f7e7f7SEdgar E. Iglesias 514f0f7e7f7SEdgar E. Iglesias /* Extended MSRs are only available if addr_size > 32. */ 515f0f7e7f7SEdgar E. Iglesias if (dc->cpu->cfg.addr_size > 32) { 516f0f7e7f7SEdgar E. Iglesias /* The E-bit is encoded differently for To/From MSR. */ 517f0f7e7f7SEdgar E. Iglesias static const unsigned int e_bit[] = { 19, 24 }; 518f0f7e7f7SEdgar E. Iglesias 519f0f7e7f7SEdgar E. Iglesias extended = extract32(dc->imm, e_bit[to], 1); 5202023e9a3SEdgar E. Iglesias } 521fcf5ef2aSThomas Huth 522fcf5ef2aSThomas Huth /* msrclr and msrset. */ 5232023e9a3SEdgar E. Iglesias if (clrset) { 5242023e9a3SEdgar E. Iglesias bool clr = extract32(dc->ir, 16, 1); 525fcf5ef2aSThomas Huth 52656837509SEdgar E. Iglesias if (!dc->cpu->cfg.use_msr_instr) { 527fcf5ef2aSThomas Huth /* nop??? */ 528fcf5ef2aSThomas Huth return; 529fcf5ef2aSThomas Huth } 530fcf5ef2aSThomas Huth 531bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) { 532fcf5ef2aSThomas Huth return; 533fcf5ef2aSThomas Huth } 534fcf5ef2aSThomas Huth 535fcf5ef2aSThomas Huth if (dc->rd) 536fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 537fcf5ef2aSThomas Huth 538cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 539cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 540fcf5ef2aSThomas Huth msr_read(dc, t0); 541cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc))); 542fcf5ef2aSThomas Huth 543fcf5ef2aSThomas Huth if (clr) { 544cfeea807SEdgar E. Iglesias tcg_gen_not_i32(t1, t1); 545cfeea807SEdgar E. Iglesias tcg_gen_and_i32(t0, t0, t1); 546fcf5ef2aSThomas Huth } else 547cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t0, t0, t1); 548fcf5ef2aSThomas Huth msr_write(dc, t0); 549cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 550cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 551d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 552d4705ae0SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 553fcf5ef2aSThomas Huth return; 554fcf5ef2aSThomas Huth } 555fcf5ef2aSThomas Huth 556bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, to)) { 557fcf5ef2aSThomas Huth return; 558fcf5ef2aSThomas Huth } 559fcf5ef2aSThomas Huth 560fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 561fcf5ef2aSThomas Huth /* Catch read/writes to the mmu block. */ 562fcf5ef2aSThomas Huth if ((sr & ~0xff) == 0x1000) { 563f0f7e7f7SEdgar E. Iglesias TCGv_i32 tmp_ext = tcg_const_i32(extended); 56405a9a651SEdgar E. Iglesias TCGv_i32 tmp_sr; 56505a9a651SEdgar E. Iglesias 566fcf5ef2aSThomas Huth sr &= 7; 56705a9a651SEdgar E. Iglesias tmp_sr = tcg_const_i32(sr); 56805a9a651SEdgar E. Iglesias if (to) { 569f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]); 57005a9a651SEdgar E. Iglesias } else { 571f0f7e7f7SEdgar E. Iglesias gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr); 57205a9a651SEdgar E. Iglesias } 57305a9a651SEdgar E. Iglesias tcg_temp_free_i32(tmp_sr); 574f0f7e7f7SEdgar E. Iglesias tcg_temp_free_i32(tmp_ext); 575fcf5ef2aSThomas Huth return; 576fcf5ef2aSThomas Huth } 577fcf5ef2aSThomas Huth #endif 578fcf5ef2aSThomas Huth 579fcf5ef2aSThomas Huth if (to) { 580fcf5ef2aSThomas Huth switch (sr) { 581aa28e6d4SRichard Henderson case SR_PC: 582fcf5ef2aSThomas Huth break; 583aa28e6d4SRichard Henderson case SR_MSR: 584fcf5ef2aSThomas Huth msr_write(dc, cpu_R[dc->ra]); 585fcf5ef2aSThomas Huth break; 586351527b7SEdgar E. Iglesias case SR_EAR: 587dbdb77c4SRichard Henderson { 588dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 589dbdb77c4SRichard Henderson tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]); 590dbdb77c4SRichard Henderson tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 591dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 592dbdb77c4SRichard Henderson } 593aa28e6d4SRichard Henderson break; 594351527b7SEdgar E. Iglesias case SR_ESR: 59541ba37c4SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 59641ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 597aa28e6d4SRichard Henderson break; 598ab6dd380SEdgar E. Iglesias case SR_FSR: 59986017ccfSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 60086017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 601aa28e6d4SRichard Henderson break; 602aa28e6d4SRichard Henderson case SR_BTR: 603ccf628b7SRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 604ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 605aa28e6d4SRichard Henderson break; 606aa28e6d4SRichard Henderson case SR_EDR: 60739db007eSRichard Henderson tcg_gen_st_i32(cpu_R[dc->ra], 60839db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 609fcf5ef2aSThomas Huth break; 610fcf5ef2aSThomas Huth case 0x800: 611cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 612cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 613fcf5ef2aSThomas Huth break; 614fcf5ef2aSThomas Huth case 0x802: 615cfeea807SEdgar E. Iglesias tcg_gen_st_i32(cpu_R[dc->ra], 616cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 617fcf5ef2aSThomas Huth break; 618fcf5ef2aSThomas Huth default: 619fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr); 620fcf5ef2aSThomas Huth break; 621fcf5ef2aSThomas Huth } 622fcf5ef2aSThomas Huth } else { 623fcf5ef2aSThomas Huth switch (sr) { 624aa28e6d4SRichard Henderson case SR_PC: 625d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 626fcf5ef2aSThomas Huth break; 627aa28e6d4SRichard Henderson case SR_MSR: 628fcf5ef2aSThomas Huth msr_read(dc, cpu_R[dc->rd]); 629fcf5ef2aSThomas Huth break; 630351527b7SEdgar E. Iglesias case SR_EAR: 631dbdb77c4SRichard Henderson { 632dbdb77c4SRichard Henderson TCGv_i64 t64 = tcg_temp_new_i64(); 633dbdb77c4SRichard Henderson tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear)); 634a1b48e3aSEdgar E. Iglesias if (extended) { 635dbdb77c4SRichard Henderson tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64); 636aa28e6d4SRichard Henderson } else { 637dbdb77c4SRichard Henderson tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64); 638dbdb77c4SRichard Henderson } 639dbdb77c4SRichard Henderson tcg_temp_free_i64(t64); 640a1b48e3aSEdgar E. Iglesias } 641aa28e6d4SRichard Henderson break; 642351527b7SEdgar E. Iglesias case SR_ESR: 64341ba37c4SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 64441ba37c4SRichard Henderson cpu_env, offsetof(CPUMBState, esr)); 645aa28e6d4SRichard Henderson break; 646351527b7SEdgar E. Iglesias case SR_FSR: 64786017ccfSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 64886017ccfSRichard Henderson cpu_env, offsetof(CPUMBState, fsr)); 649aa28e6d4SRichard Henderson break; 650351527b7SEdgar E. Iglesias case SR_BTR: 651ccf628b7SRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 652ccf628b7SRichard Henderson cpu_env, offsetof(CPUMBState, btr)); 653aa28e6d4SRichard Henderson break; 6547cdae31dSTong Ho case SR_EDR: 65539db007eSRichard Henderson tcg_gen_ld_i32(cpu_R[dc->rd], 65639db007eSRichard Henderson cpu_env, offsetof(CPUMBState, edr)); 657fcf5ef2aSThomas Huth break; 658fcf5ef2aSThomas Huth case 0x800: 659cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 660cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, slr)); 661fcf5ef2aSThomas Huth break; 662fcf5ef2aSThomas Huth case 0x802: 663cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 664cfeea807SEdgar E. Iglesias cpu_env, offsetof(CPUMBState, shr)); 665fcf5ef2aSThomas Huth break; 666351527b7SEdgar E. Iglesias case 0x2000 ... 0x200c: 667fcf5ef2aSThomas Huth rn = sr & 0xf; 668cfeea807SEdgar E. Iglesias tcg_gen_ld_i32(cpu_R[dc->rd], 669fcf5ef2aSThomas Huth cpu_env, offsetof(CPUMBState, pvr.regs[rn])); 670fcf5ef2aSThomas Huth break; 671fcf5ef2aSThomas Huth default: 672fcf5ef2aSThomas Huth cpu_abort(cs, "unknown mfs reg %x\n", sr); 673fcf5ef2aSThomas Huth break; 674fcf5ef2aSThomas Huth } 675fcf5ef2aSThomas Huth } 676fcf5ef2aSThomas Huth 677fcf5ef2aSThomas Huth if (dc->rd == 0) { 678cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[0], 0); 679fcf5ef2aSThomas Huth } 680fcf5ef2aSThomas Huth } 681fcf5ef2aSThomas Huth 682fcf5ef2aSThomas Huth /* Multiplier unit. */ 683fcf5ef2aSThomas Huth static void dec_mul(DisasContext *dc) 684fcf5ef2aSThomas Huth { 685cfeea807SEdgar E. Iglesias TCGv_i32 tmp; 686fcf5ef2aSThomas Huth unsigned int subcode; 687fcf5ef2aSThomas Huth 6889ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_hw_mul)) { 689fcf5ef2aSThomas Huth return; 690fcf5ef2aSThomas Huth } 691fcf5ef2aSThomas Huth 692fcf5ef2aSThomas Huth subcode = dc->imm & 3; 693fcf5ef2aSThomas Huth 694fcf5ef2aSThomas Huth if (dc->type_b) { 695cfeea807SEdgar E. Iglesias tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); 696fcf5ef2aSThomas Huth return; 697fcf5ef2aSThomas Huth } 698fcf5ef2aSThomas Huth 699fcf5ef2aSThomas Huth /* mulh, mulhsu and mulhu are not available if C_USE_HW_MUL is < 2. */ 7009b964318SEdgar E. Iglesias if (subcode >= 1 && subcode <= 3 && dc->cpu->cfg.use_hw_mul < 2) { 701fcf5ef2aSThomas Huth /* nop??? */ 702fcf5ef2aSThomas Huth } 703fcf5ef2aSThomas Huth 704cfeea807SEdgar E. Iglesias tmp = tcg_temp_new_i32(); 705fcf5ef2aSThomas Huth switch (subcode) { 706fcf5ef2aSThomas Huth case 0: 707cfeea807SEdgar E. Iglesias tcg_gen_mul_i32(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 708fcf5ef2aSThomas Huth break; 709fcf5ef2aSThomas Huth case 1: 710cfeea807SEdgar E. Iglesias tcg_gen_muls2_i32(tmp, cpu_R[dc->rd], 711cfeea807SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 712fcf5ef2aSThomas Huth break; 713fcf5ef2aSThomas Huth case 2: 714cfeea807SEdgar E. Iglesias tcg_gen_mulsu2_i32(tmp, cpu_R[dc->rd], 715cfeea807SEdgar E. Iglesias cpu_R[dc->ra], cpu_R[dc->rb]); 716fcf5ef2aSThomas Huth break; 717fcf5ef2aSThomas Huth case 3: 718cfeea807SEdgar E. Iglesias tcg_gen_mulu2_i32(tmp, cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); 719fcf5ef2aSThomas Huth break; 720fcf5ef2aSThomas Huth default: 721fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "unknown MUL insn %x\n", subcode); 722fcf5ef2aSThomas Huth break; 723fcf5ef2aSThomas Huth } 724cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tmp); 725fcf5ef2aSThomas Huth } 726fcf5ef2aSThomas Huth 727fcf5ef2aSThomas Huth /* Div unit. */ 728fcf5ef2aSThomas Huth static void dec_div(DisasContext *dc) 729fcf5ef2aSThomas Huth { 730fcf5ef2aSThomas Huth unsigned int u; 731fcf5ef2aSThomas Huth 732fcf5ef2aSThomas Huth u = dc->imm & 2; 733fcf5ef2aSThomas Huth 7349ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_div)) { 7359ba8cd45SEdgar E. Iglesias return; 736fcf5ef2aSThomas Huth } 737fcf5ef2aSThomas Huth 738fcf5ef2aSThomas Huth if (u) 739fcf5ef2aSThomas Huth gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), 740fcf5ef2aSThomas Huth cpu_R[dc->ra]); 741fcf5ef2aSThomas Huth else 742fcf5ef2aSThomas Huth gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), 743fcf5ef2aSThomas Huth cpu_R[dc->ra]); 744fcf5ef2aSThomas Huth if (!dc->rd) 745cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(cpu_R[dc->rd], 0); 746fcf5ef2aSThomas Huth } 747fcf5ef2aSThomas Huth 748fcf5ef2aSThomas Huth static void dec_barrel(DisasContext *dc) 749fcf5ef2aSThomas Huth { 750cfeea807SEdgar E. Iglesias TCGv_i32 t0; 751faa48d74SEdgar E. Iglesias unsigned int imm_w, imm_s; 752d09b2585SEdgar E. Iglesias bool s, t, e = false, i = false; 753fcf5ef2aSThomas Huth 7549ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_barrel)) { 755fcf5ef2aSThomas Huth return; 756fcf5ef2aSThomas Huth } 757fcf5ef2aSThomas Huth 758faa48d74SEdgar E. Iglesias if (dc->type_b) { 759faa48d74SEdgar E. Iglesias /* Insert and extract are only available in immediate mode. */ 760d09b2585SEdgar E. Iglesias i = extract32(dc->imm, 15, 1); 761faa48d74SEdgar E. Iglesias e = extract32(dc->imm, 14, 1); 762faa48d74SEdgar E. Iglesias } 763e3e84983SEdgar E. Iglesias s = extract32(dc->imm, 10, 1); 764e3e84983SEdgar E. Iglesias t = extract32(dc->imm, 9, 1); 765faa48d74SEdgar E. Iglesias imm_w = extract32(dc->imm, 6, 5); 766faa48d74SEdgar E. Iglesias imm_s = extract32(dc->imm, 0, 5); 767fcf5ef2aSThomas Huth 768faa48d74SEdgar E. Iglesias if (e) { 769faa48d74SEdgar E. Iglesias if (imm_w + imm_s > 32 || imm_w == 0) { 770faa48d74SEdgar E. Iglesias /* These inputs have an undefined behavior. */ 771faa48d74SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n", 772faa48d74SEdgar E. Iglesias imm_w, imm_s); 773faa48d74SEdgar E. Iglesias } else { 774faa48d74SEdgar E. Iglesias tcg_gen_extract_i32(cpu_R[dc->rd], cpu_R[dc->ra], imm_s, imm_w); 775faa48d74SEdgar E. Iglesias } 776d09b2585SEdgar E. Iglesias } else if (i) { 777d09b2585SEdgar E. Iglesias int width = imm_w - imm_s + 1; 778d09b2585SEdgar E. Iglesias 779d09b2585SEdgar E. Iglesias if (imm_w < imm_s) { 780d09b2585SEdgar E. Iglesias /* These inputs have an undefined behavior. */ 781d09b2585SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n", 782d09b2585SEdgar E. Iglesias imm_w, imm_s); 783d09b2585SEdgar E. Iglesias } else { 784d09b2585SEdgar E. Iglesias tcg_gen_deposit_i32(cpu_R[dc->rd], cpu_R[dc->rd], cpu_R[dc->ra], 785d09b2585SEdgar E. Iglesias imm_s, width); 786d09b2585SEdgar E. Iglesias } 787faa48d74SEdgar E. Iglesias } else { 788cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 789fcf5ef2aSThomas Huth 790cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(t0, *(dec_alu_op_b(dc))); 791cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, 31); 792fcf5ef2aSThomas Huth 7932acf6d53SEdgar E. Iglesias if (s) { 794cfeea807SEdgar E. Iglesias tcg_gen_shl_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7952acf6d53SEdgar E. Iglesias } else { 7962acf6d53SEdgar E. Iglesias if (t) { 797cfeea807SEdgar E. Iglesias tcg_gen_sar_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 7982acf6d53SEdgar E. Iglesias } else { 799cfeea807SEdgar E. Iglesias tcg_gen_shr_i32(cpu_R[dc->rd], cpu_R[dc->ra], t0); 800fcf5ef2aSThomas Huth } 801fcf5ef2aSThomas Huth } 802cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 8032acf6d53SEdgar E. Iglesias } 804faa48d74SEdgar E. Iglesias } 805fcf5ef2aSThomas Huth 806fcf5ef2aSThomas Huth static void dec_bit(DisasContext *dc) 807fcf5ef2aSThomas Huth { 808fcf5ef2aSThomas Huth CPUState *cs = CPU(dc->cpu); 809cfeea807SEdgar E. Iglesias TCGv_i32 t0; 810fcf5ef2aSThomas Huth unsigned int op; 811fcf5ef2aSThomas Huth 812fcf5ef2aSThomas Huth op = dc->ir & ((1 << 9) - 1); 813fcf5ef2aSThomas Huth switch (op) { 814fcf5ef2aSThomas Huth case 0x21: 815fcf5ef2aSThomas Huth /* src. */ 816cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 817fcf5ef2aSThomas Huth 8181074c0fbSRichard Henderson tcg_gen_shli_i32(t0, cpu_msr_c, 31); 8191074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); 820fcf5ef2aSThomas Huth if (dc->rd) { 821cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 822cfeea807SEdgar E. Iglesias tcg_gen_or_i32(cpu_R[dc->rd], cpu_R[dc->rd], t0); 823fcf5ef2aSThomas Huth } 824cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 825fcf5ef2aSThomas Huth break; 826fcf5ef2aSThomas Huth 827fcf5ef2aSThomas Huth case 0x1: 828fcf5ef2aSThomas Huth case 0x41: 829fcf5ef2aSThomas Huth /* srl. */ 8301074c0fbSRichard Henderson tcg_gen_andi_i32(cpu_msr_c, cpu_R[dc->ra], 1); 831fcf5ef2aSThomas Huth if (dc->rd) { 832fcf5ef2aSThomas Huth if (op == 0x41) 833cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 834fcf5ef2aSThomas Huth else 835cfeea807SEdgar E. Iglesias tcg_gen_sari_i32(cpu_R[dc->rd], cpu_R[dc->ra], 1); 836fcf5ef2aSThomas Huth } 837fcf5ef2aSThomas Huth break; 838fcf5ef2aSThomas Huth case 0x60: 839fcf5ef2aSThomas Huth tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 840fcf5ef2aSThomas Huth break; 841fcf5ef2aSThomas Huth case 0x61: 842fcf5ef2aSThomas Huth tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 843fcf5ef2aSThomas Huth break; 844fcf5ef2aSThomas Huth case 0x64: 845fcf5ef2aSThomas Huth case 0x66: 846fcf5ef2aSThomas Huth case 0x74: 847fcf5ef2aSThomas Huth case 0x76: 848fcf5ef2aSThomas Huth /* wdc. */ 849bdfc1e88SEdgar E. Iglesias trap_userspace(dc, true); 850fcf5ef2aSThomas Huth break; 851fcf5ef2aSThomas Huth case 0x68: 852fcf5ef2aSThomas Huth /* wic. */ 853bdfc1e88SEdgar E. Iglesias trap_userspace(dc, true); 854fcf5ef2aSThomas Huth break; 855fcf5ef2aSThomas Huth case 0xe0: 8569ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_pcmp_instr)) { 8579ba8cd45SEdgar E. Iglesias return; 858fcf5ef2aSThomas Huth } 8598fc5239eSEdgar E. Iglesias if (dc->cpu->cfg.use_pcmp_instr) { 8605318420cSRichard Henderson tcg_gen_clzi_i32(cpu_R[dc->rd], cpu_R[dc->ra], 32); 861fcf5ef2aSThomas Huth } 862fcf5ef2aSThomas Huth break; 863fcf5ef2aSThomas Huth case 0x1e0: 864fcf5ef2aSThomas Huth /* swapb */ 865fcf5ef2aSThomas Huth tcg_gen_bswap32_i32(cpu_R[dc->rd], cpu_R[dc->ra]); 866fcf5ef2aSThomas Huth break; 867fcf5ef2aSThomas Huth case 0x1e2: 868fcf5ef2aSThomas Huth /*swaph */ 869fcf5ef2aSThomas Huth tcg_gen_rotri_i32(cpu_R[dc->rd], cpu_R[dc->ra], 16); 870fcf5ef2aSThomas Huth break; 871fcf5ef2aSThomas Huth default: 872fcf5ef2aSThomas Huth cpu_abort(cs, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", 873d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, op, dc->rd, dc->ra, dc->rb); 874fcf5ef2aSThomas Huth break; 875fcf5ef2aSThomas Huth } 876fcf5ef2aSThomas Huth } 877fcf5ef2aSThomas Huth 878fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc) 879fcf5ef2aSThomas Huth { 880fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) { 881fcf5ef2aSThomas Huth if (dc->jmp == JMP_DIRECT) { 8829b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 883fcf5ef2aSThomas Huth } 884fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 8850f96e96bSRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 886fcf5ef2aSThomas Huth } 887fcf5ef2aSThomas Huth } 888fcf5ef2aSThomas Huth 889fcf5ef2aSThomas Huth static void dec_imm(DisasContext *dc) 890fcf5ef2aSThomas Huth { 891d7ecb757SRichard Henderson dc->ext_imm = dc->imm << 16; 892d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_imm, dc->ext_imm); 893fcf5ef2aSThomas Huth dc->tb_flags |= IMM_FLAG; 894fcf5ef2aSThomas Huth dc->clear_imm = 0; 895fcf5ef2aSThomas Huth } 896fcf5ef2aSThomas Huth 897d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t) 898fcf5ef2aSThomas Huth { 8990e9033c8SEdgar E. Iglesias /* Should be set to true if r1 is used by loadstores. */ 9000e9033c8SEdgar E. Iglesias bool stackprot = false; 901403322eaSEdgar E. Iglesias TCGv_i32 t32; 902fcf5ef2aSThomas Huth 903fcf5ef2aSThomas Huth /* All load/stores use ra. */ 904fcf5ef2aSThomas Huth if (dc->ra == 1 && dc->cpu->cfg.stackprot) { 9050e9033c8SEdgar E. Iglesias stackprot = true; 906fcf5ef2aSThomas Huth } 907fcf5ef2aSThomas Huth 908fcf5ef2aSThomas Huth /* Treat the common cases first. */ 909fcf5ef2aSThomas Huth if (!dc->type_b) { 910d248e1beSEdgar E. Iglesias if (ea) { 911d248e1beSEdgar E. Iglesias int addr_size = dc->cpu->cfg.addr_size; 912d248e1beSEdgar E. Iglesias 913d248e1beSEdgar E. Iglesias if (addr_size == 32) { 914d248e1beSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 915d248e1beSEdgar E. Iglesias return; 916d248e1beSEdgar E. Iglesias } 917d248e1beSEdgar E. Iglesias 918d248e1beSEdgar E. Iglesias tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]); 919d248e1beSEdgar E. Iglesias if (addr_size < 64) { 920d248e1beSEdgar E. Iglesias /* Mask off out of range bits. */ 921d248e1beSEdgar E. Iglesias tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size)); 922d248e1beSEdgar E. Iglesias } 923d248e1beSEdgar E. Iglesias return; 924d248e1beSEdgar E. Iglesias } 925d248e1beSEdgar E. Iglesias 9260dc4af5cSEdgar E. Iglesias /* If any of the regs is r0, set t to the value of the other reg. */ 927fcf5ef2aSThomas Huth if (dc->ra == 0) { 928403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]); 9290dc4af5cSEdgar E. Iglesias return; 930fcf5ef2aSThomas Huth } else if (dc->rb == 0) { 931403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]); 9320dc4af5cSEdgar E. Iglesias return; 933fcf5ef2aSThomas Huth } 934fcf5ef2aSThomas Huth 935fcf5ef2aSThomas Huth if (dc->rb == 1 && dc->cpu->cfg.stackprot) { 9360e9033c8SEdgar E. Iglesias stackprot = true; 937fcf5ef2aSThomas Huth } 938fcf5ef2aSThomas Huth 939403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 940403322eaSEdgar E. Iglesias tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]); 941403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 942403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 943fcf5ef2aSThomas Huth 944fcf5ef2aSThomas Huth if (stackprot) { 9450a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 946fcf5ef2aSThomas Huth } 9470dc4af5cSEdgar E. Iglesias return; 948fcf5ef2aSThomas Huth } 949fcf5ef2aSThomas Huth /* Immediate. */ 950403322eaSEdgar E. Iglesias t32 = tcg_temp_new_i32(); 951d7ecb757SRichard Henderson tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc)); 952403322eaSEdgar E. Iglesias tcg_gen_extu_i32_tl(t, t32); 953403322eaSEdgar E. Iglesias tcg_temp_free_i32(t32); 954fcf5ef2aSThomas Huth 955fcf5ef2aSThomas Huth if (stackprot) { 9560a87e691SEdgar E. Iglesias gen_helper_stackprot(cpu_env, t); 957fcf5ef2aSThomas Huth } 9580dc4af5cSEdgar E. Iglesias return; 959fcf5ef2aSThomas Huth } 960fcf5ef2aSThomas Huth 961fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc) 962fcf5ef2aSThomas Huth { 963403322eaSEdgar E. Iglesias TCGv_i32 v; 964403322eaSEdgar E. Iglesias TCGv addr; 9658534063aSEdgar E. Iglesias unsigned int size; 966d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 967d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 96814776ab5STony Nguyen MemOp mop; 969fcf5ef2aSThomas Huth 970fcf5ef2aSThomas Huth mop = dc->opcode & 3; 971fcf5ef2aSThomas Huth size = 1 << mop; 972fcf5ef2aSThomas Huth if (!dc->type_b) { 973d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 9748534063aSEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 9758534063aSEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 976fcf5ef2aSThomas Huth } 977fcf5ef2aSThomas Huth mop |= MO_TE; 978fcf5ef2aSThomas Huth if (rev) { 979fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 980fcf5ef2aSThomas Huth } 981fcf5ef2aSThomas Huth 9829ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 983fcf5ef2aSThomas Huth return; 984fcf5ef2aSThomas Huth } 985fcf5ef2aSThomas Huth 986d248e1beSEdgar E. Iglesias if (trap_userspace(dc, ea)) { 987d248e1beSEdgar E. Iglesias return; 988d248e1beSEdgar E. Iglesias } 989d248e1beSEdgar E. Iglesias 990fcf5ef2aSThomas Huth t_sync_flags(dc); 991403322eaSEdgar E. Iglesias addr = tcg_temp_new(); 992d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 993d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 994d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 995fcf5ef2aSThomas Huth 996fcf5ef2aSThomas Huth /* 997fcf5ef2aSThomas Huth * When doing reverse accesses we need to do two things. 998fcf5ef2aSThomas Huth * 999fcf5ef2aSThomas Huth * 1. Reverse the address wrt endianness. 1000fcf5ef2aSThomas Huth * 2. Byteswap the data lanes on the way back into the CPU core. 1001fcf5ef2aSThomas Huth */ 1002fcf5ef2aSThomas Huth if (rev && size != 4) { 1003fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 1004fcf5ef2aSThomas Huth switch (size) { 1005fcf5ef2aSThomas Huth case 1: 1006fcf5ef2aSThomas Huth { 1007a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 1008fcf5ef2aSThomas Huth break; 1009fcf5ef2aSThomas Huth } 1010fcf5ef2aSThomas Huth 1011fcf5ef2aSThomas Huth case 2: 1012fcf5ef2aSThomas Huth /* 00 -> 10 1013fcf5ef2aSThomas Huth 10 -> 00. */ 1014403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 1015fcf5ef2aSThomas Huth break; 1016fcf5ef2aSThomas Huth default: 1017fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 1018fcf5ef2aSThomas Huth break; 1019fcf5ef2aSThomas Huth } 1020fcf5ef2aSThomas Huth } 1021fcf5ef2aSThomas Huth 1022fcf5ef2aSThomas Huth /* lwx does not throw unaligned access errors, so force alignment */ 1023fcf5ef2aSThomas Huth if (ex) { 1024403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 1025fcf5ef2aSThomas Huth } 1026fcf5ef2aSThomas Huth 1027fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 1028fcf5ef2aSThomas Huth sync_jmpstate(dc); 1029fcf5ef2aSThomas Huth 1030fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 1031fcf5ef2aSThomas Huth /* 1032fcf5ef2aSThomas Huth * Microblaze gives MMU faults priority over faults due to 1033fcf5ef2aSThomas Huth * unaligned addresses. That's why we speculatively do the load 1034fcf5ef2aSThomas Huth * into v. If the load succeeds, we verify alignment of the 1035fcf5ef2aSThomas Huth * address and if that succeeds we write into the destination reg. 1036fcf5ef2aSThomas Huth */ 1037cfeea807SEdgar E. Iglesias v = tcg_temp_new_i32(); 1038d248e1beSEdgar E. Iglesias tcg_gen_qemu_ld_i32(v, addr, mem_index, mop); 1039fcf5ef2aSThomas Huth 10401507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1041a6338015SEdgar E. Iglesias TCGv_i32 t0 = tcg_const_i32(0); 1042a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1043a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1044a6338015SEdgar E. Iglesias 1045d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1046a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t0, tsize); 1047a6338015SEdgar E. Iglesias 1048a6338015SEdgar E. Iglesias tcg_temp_free_i32(t0); 1049a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1050a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1051fcf5ef2aSThomas Huth } 1052fcf5ef2aSThomas Huth 1053fcf5ef2aSThomas Huth if (ex) { 10549b158558SRichard Henderson tcg_gen_mov_tl(cpu_res_addr, addr); 10559b158558SRichard Henderson tcg_gen_mov_i32(cpu_res_val, v); 1056fcf5ef2aSThomas Huth } 1057fcf5ef2aSThomas Huth if (dc->rd) { 1058cfeea807SEdgar E. Iglesias tcg_gen_mov_i32(cpu_R[dc->rd], v); 1059fcf5ef2aSThomas Huth } 1060cfeea807SEdgar E. Iglesias tcg_temp_free_i32(v); 1061fcf5ef2aSThomas Huth 1062fcf5ef2aSThomas Huth if (ex) { /* lwx */ 1063fcf5ef2aSThomas Huth /* no support for AXI exclusive so always clear C */ 10641074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1065fcf5ef2aSThomas Huth } 1066fcf5ef2aSThomas Huth 1067403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1068fcf5ef2aSThomas Huth } 1069fcf5ef2aSThomas Huth 1070fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc) 1071fcf5ef2aSThomas Huth { 1072403322eaSEdgar E. Iglesias TCGv addr; 1073fcf5ef2aSThomas Huth TCGLabel *swx_skip = NULL; 1074b51b3d43SEdgar E. Iglesias unsigned int size; 1075d248e1beSEdgar E. Iglesias bool rev = false, ex = false, ea = false; 1076d248e1beSEdgar E. Iglesias int mem_index = cpu_mmu_index(&dc->cpu->env, false); 107714776ab5STony Nguyen MemOp mop; 1078fcf5ef2aSThomas Huth 1079fcf5ef2aSThomas Huth mop = dc->opcode & 3; 1080fcf5ef2aSThomas Huth size = 1 << mop; 1081fcf5ef2aSThomas Huth if (!dc->type_b) { 1082d248e1beSEdgar E. Iglesias ea = extract32(dc->ir, 7, 1); 1083b51b3d43SEdgar E. Iglesias rev = extract32(dc->ir, 9, 1); 1084b51b3d43SEdgar E. Iglesias ex = extract32(dc->ir, 10, 1); 1085fcf5ef2aSThomas Huth } 1086fcf5ef2aSThomas Huth mop |= MO_TE; 1087fcf5ef2aSThomas Huth if (rev) { 1088fcf5ef2aSThomas Huth mop ^= MO_BSWAP; 1089fcf5ef2aSThomas Huth } 1090fcf5ef2aSThomas Huth 10919ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, size > 4)) { 1092fcf5ef2aSThomas Huth return; 1093fcf5ef2aSThomas Huth } 1094fcf5ef2aSThomas Huth 1095d248e1beSEdgar E. Iglesias trap_userspace(dc, ea); 1096d248e1beSEdgar E. Iglesias 1097fcf5ef2aSThomas Huth t_sync_flags(dc); 1098fcf5ef2aSThomas Huth /* If we get a fault on a dslot, the jmpstate better be in sync. */ 1099fcf5ef2aSThomas Huth sync_jmpstate(dc); 11000dc4af5cSEdgar E. Iglesias /* SWX needs a temp_local. */ 1101403322eaSEdgar E. Iglesias addr = ex ? tcg_temp_local_new() : tcg_temp_new(); 1102d248e1beSEdgar E. Iglesias compute_ldst_addr(dc, ea, addr); 1103d248e1beSEdgar E. Iglesias /* Extended addressing bypasses the MMU. */ 1104d248e1beSEdgar E. Iglesias mem_index = ea ? MMU_NOMMU_IDX : mem_index; 1105fcf5ef2aSThomas Huth 1106fcf5ef2aSThomas Huth if (ex) { /* swx */ 1107cfeea807SEdgar E. Iglesias TCGv_i32 tval; 1108fcf5ef2aSThomas Huth 1109fcf5ef2aSThomas Huth /* swx does not throw unaligned access errors, so force alignment */ 1110403322eaSEdgar E. Iglesias tcg_gen_andi_tl(addr, addr, ~3); 1111fcf5ef2aSThomas Huth 11121074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 1); 1113fcf5ef2aSThomas Huth swx_skip = gen_new_label(); 11149b158558SRichard Henderson tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip); 1115fcf5ef2aSThomas Huth 1116071cdc67SEdgar E. Iglesias /* 1117071cdc67SEdgar E. Iglesias * Compare the value loaded at lwx with current contents of 1118071cdc67SEdgar E. Iglesias * the reserved location. 1119071cdc67SEdgar E. Iglesias */ 1120cfeea807SEdgar E. Iglesias tval = tcg_temp_new_i32(); 1121071cdc67SEdgar E. Iglesias 11229b158558SRichard Henderson tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val, 1123071cdc67SEdgar E. Iglesias cpu_R[dc->rd], mem_index, 1124071cdc67SEdgar E. Iglesias mop); 1125071cdc67SEdgar E. Iglesias 11269b158558SRichard Henderson tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip); 11271074c0fbSRichard Henderson tcg_gen_movi_i32(cpu_msr_c, 0); 1128cfeea807SEdgar E. Iglesias tcg_temp_free_i32(tval); 1129fcf5ef2aSThomas Huth } 1130fcf5ef2aSThomas Huth 1131fcf5ef2aSThomas Huth if (rev && size != 4) { 1132fcf5ef2aSThomas Huth /* Endian reverse the address. t is addr. */ 1133fcf5ef2aSThomas Huth switch (size) { 1134fcf5ef2aSThomas Huth case 1: 1135fcf5ef2aSThomas Huth { 1136a6338015SEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 3); 1137fcf5ef2aSThomas Huth break; 1138fcf5ef2aSThomas Huth } 1139fcf5ef2aSThomas Huth 1140fcf5ef2aSThomas Huth case 2: 1141fcf5ef2aSThomas Huth /* 00 -> 10 1142fcf5ef2aSThomas Huth 10 -> 00. */ 1143fcf5ef2aSThomas Huth /* Force addr into the temp. */ 1144403322eaSEdgar E. Iglesias tcg_gen_xori_tl(addr, addr, 2); 1145fcf5ef2aSThomas Huth break; 1146fcf5ef2aSThomas Huth default: 1147fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Invalid reverse size\n"); 1148fcf5ef2aSThomas Huth break; 1149fcf5ef2aSThomas Huth } 1150fcf5ef2aSThomas Huth } 1151071cdc67SEdgar E. Iglesias 1152071cdc67SEdgar E. Iglesias if (!ex) { 1153d248e1beSEdgar E. Iglesias tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop); 1154071cdc67SEdgar E. Iglesias } 1155fcf5ef2aSThomas Huth 1156fcf5ef2aSThomas Huth /* Verify alignment if needed. */ 11571507e5f6SEdgar E. Iglesias if (dc->cpu->cfg.unaligned_exceptions && size > 1) { 1158a6338015SEdgar E. Iglesias TCGv_i32 t1 = tcg_const_i32(1); 1159a6338015SEdgar E. Iglesias TCGv_i32 treg = tcg_const_i32(dc->rd); 1160a6338015SEdgar E. Iglesias TCGv_i32 tsize = tcg_const_i32(size - 1); 1161a6338015SEdgar E. Iglesias 1162d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1163fcf5ef2aSThomas Huth /* FIXME: if the alignment is wrong, we should restore the value 1164fcf5ef2aSThomas Huth * in memory. One possible way to achieve this is to probe 1165fcf5ef2aSThomas Huth * the MMU prior to the memaccess, thay way we could put 1166fcf5ef2aSThomas Huth * the alignment checks in between the probe and the mem 1167fcf5ef2aSThomas Huth * access. 1168fcf5ef2aSThomas Huth */ 1169a6338015SEdgar E. Iglesias gen_helper_memalign(cpu_env, addr, treg, t1, tsize); 1170a6338015SEdgar E. Iglesias 1171a6338015SEdgar E. Iglesias tcg_temp_free_i32(t1); 1172a6338015SEdgar E. Iglesias tcg_temp_free_i32(treg); 1173a6338015SEdgar E. Iglesias tcg_temp_free_i32(tsize); 1174fcf5ef2aSThomas Huth } 1175fcf5ef2aSThomas Huth 1176fcf5ef2aSThomas Huth if (ex) { 1177fcf5ef2aSThomas Huth gen_set_label(swx_skip); 1178fcf5ef2aSThomas Huth } 1179fcf5ef2aSThomas Huth 1180403322eaSEdgar E. Iglesias tcg_temp_free(addr); 1181fcf5ef2aSThomas Huth } 1182fcf5ef2aSThomas Huth 1183fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc, 11849e6e1828SEdgar E. Iglesias TCGv_i32 d, TCGv_i32 a) 1185fcf5ef2aSThomas Huth { 1186d89b86e9SEdgar E. Iglesias static const int mb_to_tcg_cc[] = { 1187d89b86e9SEdgar E. Iglesias [CC_EQ] = TCG_COND_EQ, 1188d89b86e9SEdgar E. Iglesias [CC_NE] = TCG_COND_NE, 1189d89b86e9SEdgar E. Iglesias [CC_LT] = TCG_COND_LT, 1190d89b86e9SEdgar E. Iglesias [CC_LE] = TCG_COND_LE, 1191d89b86e9SEdgar E. Iglesias [CC_GE] = TCG_COND_GE, 1192d89b86e9SEdgar E. Iglesias [CC_GT] = TCG_COND_GT, 1193d89b86e9SEdgar E. Iglesias }; 1194d89b86e9SEdgar E. Iglesias 1195fcf5ef2aSThomas Huth switch (cc) { 1196fcf5ef2aSThomas Huth case CC_EQ: 1197fcf5ef2aSThomas Huth case CC_NE: 1198fcf5ef2aSThomas Huth case CC_LT: 1199fcf5ef2aSThomas Huth case CC_LE: 1200fcf5ef2aSThomas Huth case CC_GE: 1201fcf5ef2aSThomas Huth case CC_GT: 12029e6e1828SEdgar E. Iglesias tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0); 1203fcf5ef2aSThomas Huth break; 1204fcf5ef2aSThomas Huth default: 1205fcf5ef2aSThomas Huth cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc); 1206fcf5ef2aSThomas Huth break; 1207fcf5ef2aSThomas Huth } 1208fcf5ef2aSThomas Huth } 1209fcf5ef2aSThomas Huth 12100f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false) 1211fcf5ef2aSThomas Huth { 12120f96e96bSRichard Henderson TCGv_i32 zero = tcg_const_i32(0); 1213e956caf2SEdgar E. Iglesias 12140f96e96bSRichard Henderson tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc, 12159b158558SRichard Henderson cpu_btaken, zero, 1216e956caf2SEdgar E. Iglesias pc_true, pc_false); 1217e956caf2SEdgar E. Iglesias 12180f96e96bSRichard Henderson tcg_temp_free_i32(zero); 1219fcf5ef2aSThomas Huth } 1220fcf5ef2aSThomas Huth 1221f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc) 1222f91c60f0SEdgar E. Iglesias { 1223f91c60f0SEdgar E. Iglesias TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG)); 1224f91c60f0SEdgar E. Iglesias 1225f91c60f0SEdgar E. Iglesias dc->delayed_branch = 2; 1226f91c60f0SEdgar E. Iglesias dc->tb_flags |= D_FLAG; 1227f91c60f0SEdgar E. Iglesias 1228f91c60f0SEdgar E. Iglesias tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm)); 1229f91c60f0SEdgar E. Iglesias tcg_temp_free_i32(tmp); 1230f91c60f0SEdgar E. Iglesias } 1231f91c60f0SEdgar E. Iglesias 1232fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc) 1233fcf5ef2aSThomas Huth { 1234fcf5ef2aSThomas Huth unsigned int cc; 1235fcf5ef2aSThomas Huth unsigned int dslot; 1236fcf5ef2aSThomas Huth 1237fcf5ef2aSThomas Huth cc = EXTRACT_FIELD(dc->ir, 21, 23); 1238fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 25); 1239fcf5ef2aSThomas Huth 1240fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1241fcf5ef2aSThomas Huth if (dslot) { 1242f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1243fcf5ef2aSThomas Huth } 1244fcf5ef2aSThomas Huth 1245d7ecb757SRichard Henderson if (dc->type_b) { 1246fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT_CC; 1247d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1248d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1249fcf5ef2aSThomas Huth } else { 1250fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 1251d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1252fcf5ef2aSThomas Huth } 12539b158558SRichard Henderson eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]); 1254fcf5ef2aSThomas Huth } 1255fcf5ef2aSThomas Huth 1256fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc) 1257fcf5ef2aSThomas Huth { 1258fcf5ef2aSThomas Huth unsigned int dslot, link, abs, mbar; 1259fcf5ef2aSThomas Huth 1260fcf5ef2aSThomas Huth dslot = dc->ir & (1 << 20); 1261fcf5ef2aSThomas Huth abs = dc->ir & (1 << 19); 1262fcf5ef2aSThomas Huth link = dc->ir & (1 << 18); 1263fcf5ef2aSThomas Huth 1264fcf5ef2aSThomas Huth /* Memory barrier. */ 1265fcf5ef2aSThomas Huth mbar = (dc->ir >> 16) & 31; 1266fcf5ef2aSThomas Huth if (mbar == 2 && dc->imm == 4) { 1267badcbf9dSEdgar E. Iglesias uint16_t mbar_imm = dc->rd; 1268badcbf9dSEdgar E. Iglesias 12693f172744SEdgar E. Iglesias /* Data access memory barrier. */ 12703f172744SEdgar E. Iglesias if ((mbar_imm & 2) == 0) { 12713f172744SEdgar E. Iglesias tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL); 12723f172744SEdgar E. Iglesias } 12733f172744SEdgar E. Iglesias 1274fcf5ef2aSThomas Huth /* mbar IMM & 16 decodes to sleep. */ 1275badcbf9dSEdgar E. Iglesias if (mbar_imm & 16) { 127641ba37c4SRichard Henderson TCGv_i32 tmp_1; 1277fcf5ef2aSThomas Huth 1278b4919e7dSEdgar E. Iglesias if (trap_userspace(dc, true)) { 1279b4919e7dSEdgar E. Iglesias /* Sleep is a privileged instruction. */ 1280b4919e7dSEdgar E. Iglesias return; 1281b4919e7dSEdgar E. Iglesias } 1282b4919e7dSEdgar E. Iglesias 1283fcf5ef2aSThomas Huth t_sync_flags(dc); 128441ba37c4SRichard Henderson 128541ba37c4SRichard Henderson tmp_1 = tcg_const_i32(1); 1286fcf5ef2aSThomas Huth tcg_gen_st_i32(tmp_1, cpu_env, 1287fcf5ef2aSThomas Huth -offsetof(MicroBlazeCPU, env) 1288fcf5ef2aSThomas Huth +offsetof(CPUState, halted)); 1289fcf5ef2aSThomas Huth tcg_temp_free_i32(tmp_1); 129041ba37c4SRichard Henderson 1291d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4); 129241ba37c4SRichard Henderson 129341ba37c4SRichard Henderson gen_raise_exception(dc, EXCP_HLT); 1294fcf5ef2aSThomas Huth return; 1295fcf5ef2aSThomas Huth } 1296fcf5ef2aSThomas Huth /* Break the TB. */ 1297fcf5ef2aSThomas Huth dc->cpustate_changed = 1; 1298fcf5ef2aSThomas Huth return; 1299fcf5ef2aSThomas Huth } 1300fcf5ef2aSThomas Huth 1301d7ecb757SRichard Henderson if (abs && link && !dslot) { 1302d7ecb757SRichard Henderson if (dc->type_b) { 1303d7ecb757SRichard Henderson /* BRKI */ 1304d7ecb757SRichard Henderson uint32_t imm = dec_alu_typeb_imm(dc); 1305d7ecb757SRichard Henderson if (trap_userspace(dc, imm != 8 && imm != 0x18)) { 1306d7ecb757SRichard Henderson return; 1307d7ecb757SRichard Henderson } 1308d7ecb757SRichard Henderson } else { 1309d7ecb757SRichard Henderson /* BRK */ 1310d7ecb757SRichard Henderson if (trap_userspace(dc, true)) { 1311d7ecb757SRichard Henderson return; 1312d7ecb757SRichard Henderson } 1313d7ecb757SRichard Henderson } 1314d7ecb757SRichard Henderson } 1315d7ecb757SRichard Henderson 1316fcf5ef2aSThomas Huth dc->delayed_branch = 1; 1317fcf5ef2aSThomas Huth if (dslot) { 1318f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1319fcf5ef2aSThomas Huth } 1320d7ecb757SRichard Henderson if (link && dc->rd) { 1321d4705ae0SRichard Henderson tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next); 1322d7ecb757SRichard Henderson } 1323fcf5ef2aSThomas Huth 1324fcf5ef2aSThomas Huth if (abs) { 1325d7ecb757SRichard Henderson if (dc->type_b) { 1326d7ecb757SRichard Henderson uint32_t dest = dec_alu_typeb_imm(dc); 1327d7ecb757SRichard Henderson 1328d7ecb757SRichard Henderson dc->jmp = JMP_DIRECT; 1329d7ecb757SRichard Henderson dc->jmp_pc = dest; 1330d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dest); 1331fcf5ef2aSThomas Huth if (link && !dslot) { 1332d7ecb757SRichard Henderson switch (dest) { 1333d7ecb757SRichard Henderson case 8: 1334d7ecb757SRichard Henderson case 0x18: 1335d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 1336d7ecb757SRichard Henderson break; 1337d7ecb757SRichard Henderson case 0: 1338d7ecb757SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1339d7ecb757SRichard Henderson break; 1340d7ecb757SRichard Henderson } 1341d7ecb757SRichard Henderson } 1342d7ecb757SRichard Henderson } else { 1343d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1344d7ecb757SRichard Henderson tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]); 1345d7ecb757SRichard Henderson if (link && !dslot) { 134641ba37c4SRichard Henderson gen_raise_exception_sync(dc, EXCP_BREAK); 134741ba37c4SRichard Henderson } 1348fcf5ef2aSThomas Huth } 1349d7ecb757SRichard Henderson } else if (dc->type_b) { 1350fcf5ef2aSThomas Huth dc->jmp = JMP_DIRECT; 1351d7ecb757SRichard Henderson dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc); 1352d7ecb757SRichard Henderson tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc); 1353fcf5ef2aSThomas Huth } else { 1354d7ecb757SRichard Henderson dc->jmp = JMP_INDIRECT; 1355d7ecb757SRichard Henderson tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next); 1356d7ecb757SRichard Henderson } 13579b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 1358fcf5ef2aSThomas Huth } 1359fcf5ef2aSThomas Huth 1360fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc) 1361fcf5ef2aSThomas Huth { 1362cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1363cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1364cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13653e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13660a22f8cfSEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 13670a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_IE); 1368cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1369fcf5ef2aSThomas Huth 1370cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1371cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1372fcf5ef2aSThomas Huth msr_write(dc, t1); 1373cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1374cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1375fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTI_FLAG; 1376fcf5ef2aSThomas Huth } 1377fcf5ef2aSThomas Huth 1378fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc) 1379fcf5ef2aSThomas Huth { 1380cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1381cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1382cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 13833e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 13840a22f8cfSEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_BIP); 1385cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1386cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1387fcf5ef2aSThomas Huth 1388cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1389cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1390fcf5ef2aSThomas Huth msr_write(dc, t1); 1391cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1392cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1393fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTB_FLAG; 1394fcf5ef2aSThomas Huth } 1395fcf5ef2aSThomas Huth 1396fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc) 1397fcf5ef2aSThomas Huth { 1398cfeea807SEdgar E. Iglesias TCGv_i32 t0, t1; 1399cfeea807SEdgar E. Iglesias t0 = tcg_temp_new_i32(); 1400cfeea807SEdgar E. Iglesias t1 = tcg_temp_new_i32(); 1401fcf5ef2aSThomas Huth 14023e0e16aeSRichard Henderson tcg_gen_mov_i32(t1, cpu_msr); 14030a22f8cfSEdgar E. Iglesias tcg_gen_ori_i32(t1, t1, MSR_EE); 1404cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~MSR_EIP); 1405cfeea807SEdgar E. Iglesias tcg_gen_shri_i32(t0, t1, 1); 1406cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM)); 1407fcf5ef2aSThomas Huth 1408cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM)); 1409cfeea807SEdgar E. Iglesias tcg_gen_or_i32(t1, t1, t0); 1410fcf5ef2aSThomas Huth msr_write(dc, t1); 1411cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t1); 1412cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t0); 1413fcf5ef2aSThomas Huth dc->tb_flags &= ~DRTE_FLAG; 1414fcf5ef2aSThomas Huth } 1415fcf5ef2aSThomas Huth 1416fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc) 1417fcf5ef2aSThomas Huth { 1418fcf5ef2aSThomas Huth unsigned int b_bit, i_bit, e_bit; 1419fcf5ef2aSThomas Huth 1420fcf5ef2aSThomas Huth i_bit = dc->ir & (1 << 21); 1421fcf5ef2aSThomas Huth b_bit = dc->ir & (1 << 22); 1422fcf5ef2aSThomas Huth e_bit = dc->ir & (1 << 23); 1423fcf5ef2aSThomas Huth 1424bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, i_bit || b_bit || e_bit)) { 1425bdfc1e88SEdgar E. Iglesias return; 1426bdfc1e88SEdgar E. Iglesias } 1427bdfc1e88SEdgar E. Iglesias 1428f91c60f0SEdgar E. Iglesias dec_setup_dslot(dc); 1429fcf5ef2aSThomas Huth 1430fcf5ef2aSThomas Huth if (i_bit) { 1431fcf5ef2aSThomas Huth dc->tb_flags |= DRTI_FLAG; 1432fcf5ef2aSThomas Huth } else if (b_bit) { 1433fcf5ef2aSThomas Huth dc->tb_flags |= DRTB_FLAG; 1434fcf5ef2aSThomas Huth } else if (e_bit) { 1435fcf5ef2aSThomas Huth dc->tb_flags |= DRTE_FLAG; 143611105d67SRichard Henderson } 1437fcf5ef2aSThomas Huth 1438fcf5ef2aSThomas Huth dc->jmp = JMP_INDIRECT; 14399b158558SRichard Henderson tcg_gen_movi_i32(cpu_btaken, 1); 14400f96e96bSRichard Henderson tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc)); 1441fcf5ef2aSThomas Huth } 1442fcf5ef2aSThomas Huth 1443fcf5ef2aSThomas Huth static int dec_check_fpuv2(DisasContext *dc) 1444fcf5ef2aSThomas Huth { 1445fcf5ef2aSThomas Huth if ((dc->cpu->cfg.use_fpu != 2) && (dc->tb_flags & MSR_EE_FLAG)) { 144641ba37c4SRichard Henderson gen_raise_hw_excp(dc, ESR_EC_FPU); 1447fcf5ef2aSThomas Huth } 14482016a6a7SJoe Komlodi return (dc->cpu->cfg.use_fpu == 2) ? PVR2_USE_FPU2_MASK : 0; 1449fcf5ef2aSThomas Huth } 1450fcf5ef2aSThomas Huth 1451fcf5ef2aSThomas Huth static void dec_fpu(DisasContext *dc) 1452fcf5ef2aSThomas Huth { 1453fcf5ef2aSThomas Huth unsigned int fpu_insn; 1454fcf5ef2aSThomas Huth 14559ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, !dc->cpu->cfg.use_fpu)) { 1456fcf5ef2aSThomas Huth return; 1457fcf5ef2aSThomas Huth } 1458fcf5ef2aSThomas Huth 1459fcf5ef2aSThomas Huth fpu_insn = (dc->ir >> 7) & 7; 1460fcf5ef2aSThomas Huth 1461fcf5ef2aSThomas Huth switch (fpu_insn) { 1462fcf5ef2aSThomas Huth case 0: 1463fcf5ef2aSThomas Huth gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1464fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1465fcf5ef2aSThomas Huth break; 1466fcf5ef2aSThomas Huth 1467fcf5ef2aSThomas Huth case 1: 1468fcf5ef2aSThomas Huth gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1469fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1470fcf5ef2aSThomas Huth break; 1471fcf5ef2aSThomas Huth 1472fcf5ef2aSThomas Huth case 2: 1473fcf5ef2aSThomas Huth gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1474fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1475fcf5ef2aSThomas Huth break; 1476fcf5ef2aSThomas Huth 1477fcf5ef2aSThomas Huth case 3: 1478fcf5ef2aSThomas Huth gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], 1479fcf5ef2aSThomas Huth cpu_R[dc->rb]); 1480fcf5ef2aSThomas Huth break; 1481fcf5ef2aSThomas Huth 1482fcf5ef2aSThomas Huth case 4: 1483fcf5ef2aSThomas Huth switch ((dc->ir >> 4) & 7) { 1484fcf5ef2aSThomas Huth case 0: 1485fcf5ef2aSThomas Huth gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env, 1486fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1487fcf5ef2aSThomas Huth break; 1488fcf5ef2aSThomas Huth case 1: 1489fcf5ef2aSThomas Huth gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env, 1490fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1491fcf5ef2aSThomas Huth break; 1492fcf5ef2aSThomas Huth case 2: 1493fcf5ef2aSThomas Huth gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env, 1494fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1495fcf5ef2aSThomas Huth break; 1496fcf5ef2aSThomas Huth case 3: 1497fcf5ef2aSThomas Huth gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env, 1498fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1499fcf5ef2aSThomas Huth break; 1500fcf5ef2aSThomas Huth case 4: 1501fcf5ef2aSThomas Huth gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env, 1502fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1503fcf5ef2aSThomas Huth break; 1504fcf5ef2aSThomas Huth case 5: 1505fcf5ef2aSThomas Huth gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env, 1506fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1507fcf5ef2aSThomas Huth break; 1508fcf5ef2aSThomas Huth case 6: 1509fcf5ef2aSThomas Huth gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env, 1510fcf5ef2aSThomas Huth cpu_R[dc->ra], cpu_R[dc->rb]); 1511fcf5ef2aSThomas Huth break; 1512fcf5ef2aSThomas Huth default: 1513fcf5ef2aSThomas Huth qemu_log_mask(LOG_UNIMP, 1514fcf5ef2aSThomas Huth "unimplemented fcmp fpu_insn=%x pc=%x" 1515fcf5ef2aSThomas Huth " opc=%x\n", 1516d4705ae0SRichard Henderson fpu_insn, (uint32_t)dc->base.pc_next, 1517d4705ae0SRichard Henderson dc->opcode); 1518fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1519fcf5ef2aSThomas Huth break; 1520fcf5ef2aSThomas Huth } 1521fcf5ef2aSThomas Huth break; 1522fcf5ef2aSThomas Huth 1523fcf5ef2aSThomas Huth case 5: 1524fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1525fcf5ef2aSThomas Huth return; 1526fcf5ef2aSThomas Huth } 1527fcf5ef2aSThomas Huth gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1528fcf5ef2aSThomas Huth break; 1529fcf5ef2aSThomas Huth 1530fcf5ef2aSThomas Huth case 6: 1531fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1532fcf5ef2aSThomas Huth return; 1533fcf5ef2aSThomas Huth } 1534fcf5ef2aSThomas Huth gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1535fcf5ef2aSThomas Huth break; 1536fcf5ef2aSThomas Huth 1537fcf5ef2aSThomas Huth case 7: 1538fcf5ef2aSThomas Huth if (!dec_check_fpuv2(dc)) { 1539fcf5ef2aSThomas Huth return; 1540fcf5ef2aSThomas Huth } 1541fcf5ef2aSThomas Huth gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); 1542fcf5ef2aSThomas Huth break; 1543fcf5ef2aSThomas Huth 1544fcf5ef2aSThomas Huth default: 1545fcf5ef2aSThomas Huth qemu_log_mask(LOG_UNIMP, "unimplemented FPU insn fpu_insn=%x pc=%x" 1546fcf5ef2aSThomas Huth " opc=%x\n", 1547d4705ae0SRichard Henderson fpu_insn, (uint32_t)dc->base.pc_next, dc->opcode); 1548fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1549fcf5ef2aSThomas Huth break; 1550fcf5ef2aSThomas Huth } 1551fcf5ef2aSThomas Huth } 1552fcf5ef2aSThomas Huth 1553fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc) 1554fcf5ef2aSThomas Huth { 15559ba8cd45SEdgar E. Iglesias if (trap_illegal(dc, true)) { 1556fcf5ef2aSThomas Huth return; 1557fcf5ef2aSThomas Huth } 1558d4705ae0SRichard Henderson qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n", 1559d4705ae0SRichard Henderson (uint32_t)dc->base.pc_next, dc->opcode); 1560fcf5ef2aSThomas Huth dc->abort_at_next_insn = 1; 1561fcf5ef2aSThomas Huth } 1562fcf5ef2aSThomas Huth 1563fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices. */ 1564fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc) 1565fcf5ef2aSThomas Huth { 1566fcf5ef2aSThomas Huth TCGv_i32 t_id, t_ctrl; 1567fcf5ef2aSThomas Huth int ctrl; 1568fcf5ef2aSThomas Huth 1569bdfc1e88SEdgar E. Iglesias if (trap_userspace(dc, true)) { 1570fcf5ef2aSThomas Huth return; 1571fcf5ef2aSThomas Huth } 1572fcf5ef2aSThomas Huth 1573cfeea807SEdgar E. Iglesias t_id = tcg_temp_new_i32(); 1574fcf5ef2aSThomas Huth if (dc->type_b) { 1575cfeea807SEdgar E. Iglesias tcg_gen_movi_i32(t_id, dc->imm & 0xf); 1576fcf5ef2aSThomas Huth ctrl = dc->imm >> 10; 1577fcf5ef2aSThomas Huth } else { 1578cfeea807SEdgar E. Iglesias tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf); 1579fcf5ef2aSThomas Huth ctrl = dc->imm >> 5; 1580fcf5ef2aSThomas Huth } 1581fcf5ef2aSThomas Huth 1582cfeea807SEdgar E. Iglesias t_ctrl = tcg_const_i32(ctrl); 1583fcf5ef2aSThomas Huth 1584fcf5ef2aSThomas Huth if (dc->rd == 0) { 1585fcf5ef2aSThomas Huth gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]); 1586fcf5ef2aSThomas Huth } else { 1587fcf5ef2aSThomas Huth gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl); 1588fcf5ef2aSThomas Huth } 1589cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_id); 1590cfeea807SEdgar E. Iglesias tcg_temp_free_i32(t_ctrl); 1591fcf5ef2aSThomas Huth } 1592fcf5ef2aSThomas Huth 1593fcf5ef2aSThomas Huth static struct decoder_info { 1594fcf5ef2aSThomas Huth struct { 1595fcf5ef2aSThomas Huth uint32_t bits; 1596fcf5ef2aSThomas Huth uint32_t mask; 1597fcf5ef2aSThomas Huth }; 1598fcf5ef2aSThomas Huth void (*dec)(DisasContext *dc); 1599fcf5ef2aSThomas Huth } decinfo[] = { 1600fcf5ef2aSThomas Huth {DEC_SUB, dec_sub}, 1601fcf5ef2aSThomas Huth {DEC_AND, dec_and}, 1602fcf5ef2aSThomas Huth {DEC_XOR, dec_xor}, 1603fcf5ef2aSThomas Huth {DEC_OR, dec_or}, 1604fcf5ef2aSThomas Huth {DEC_BIT, dec_bit}, 1605fcf5ef2aSThomas Huth {DEC_BARREL, dec_barrel}, 1606fcf5ef2aSThomas Huth {DEC_LD, dec_load}, 1607fcf5ef2aSThomas Huth {DEC_ST, dec_store}, 1608fcf5ef2aSThomas Huth {DEC_IMM, dec_imm}, 1609fcf5ef2aSThomas Huth {DEC_BR, dec_br}, 1610fcf5ef2aSThomas Huth {DEC_BCC, dec_bcc}, 1611fcf5ef2aSThomas Huth {DEC_RTS, dec_rts}, 1612fcf5ef2aSThomas Huth {DEC_FPU, dec_fpu}, 1613fcf5ef2aSThomas Huth {DEC_MUL, dec_mul}, 1614fcf5ef2aSThomas Huth {DEC_DIV, dec_div}, 1615fcf5ef2aSThomas Huth {DEC_MSR, dec_msr}, 1616fcf5ef2aSThomas Huth {DEC_STREAM, dec_stream}, 1617fcf5ef2aSThomas Huth {{0, 0}, dec_null} 1618fcf5ef2aSThomas Huth }; 1619fcf5ef2aSThomas Huth 162044d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir) 1621fcf5ef2aSThomas Huth { 1622fcf5ef2aSThomas Huth int i; 1623fcf5ef2aSThomas Huth 1624fcf5ef2aSThomas Huth dc->ir = ir; 1625fcf5ef2aSThomas Huth 1626fcf5ef2aSThomas Huth /* bit 2 seems to indicate insn type. */ 1627fcf5ef2aSThomas Huth dc->type_b = ir & (1 << 29); 1628fcf5ef2aSThomas Huth 1629fcf5ef2aSThomas Huth dc->opcode = EXTRACT_FIELD(ir, 26, 31); 1630fcf5ef2aSThomas Huth dc->rd = EXTRACT_FIELD(ir, 21, 25); 1631fcf5ef2aSThomas Huth dc->ra = EXTRACT_FIELD(ir, 16, 20); 1632fcf5ef2aSThomas Huth dc->rb = EXTRACT_FIELD(ir, 11, 15); 1633fcf5ef2aSThomas Huth dc->imm = EXTRACT_FIELD(ir, 0, 15); 1634fcf5ef2aSThomas Huth 1635fcf5ef2aSThomas Huth /* Large switch for all insns. */ 1636fcf5ef2aSThomas Huth for (i = 0; i < ARRAY_SIZE(decinfo); i++) { 1637fcf5ef2aSThomas Huth if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { 1638fcf5ef2aSThomas Huth decinfo[i].dec(dc); 1639fcf5ef2aSThomas Huth break; 1640fcf5ef2aSThomas Huth } 1641fcf5ef2aSThomas Huth } 1642fcf5ef2aSThomas Huth } 1643fcf5ef2aSThomas Huth 1644372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) 1645fcf5ef2aSThomas Huth { 1646372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1647372122e3SRichard Henderson MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1648372122e3SRichard Henderson int bound; 1649fcf5ef2aSThomas Huth 1650fcf5ef2aSThomas Huth dc->cpu = cpu; 1651372122e3SRichard Henderson dc->synced_flags = dc->tb_flags = dc->base.tb->flags; 1652fcf5ef2aSThomas Huth dc->delayed_branch = !!(dc->tb_flags & D_FLAG); 1653372122e3SRichard Henderson dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP; 1654fcf5ef2aSThomas Huth dc->cpustate_changed = 0; 1655fcf5ef2aSThomas Huth dc->abort_at_next_insn = 0; 1656d7ecb757SRichard Henderson dc->ext_imm = dc->base.tb->cs_base; 1657*20800179SRichard Henderson dc->r0 = NULL; 1658*20800179SRichard Henderson dc->r0_set = false; 1659fcf5ef2aSThomas Huth 1660372122e3SRichard Henderson bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; 1661372122e3SRichard Henderson dc->base.max_insns = MIN(dc->base.max_insns, bound); 1662fcf5ef2aSThomas Huth } 1663fcf5ef2aSThomas Huth 1664372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs) 1665fcf5ef2aSThomas Huth { 1666fcf5ef2aSThomas Huth } 1667fcf5ef2aSThomas Huth 1668372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs) 1669372122e3SRichard Henderson { 1670372122e3SRichard Henderson tcg_gen_insn_start(dcb->pc_next); 1671372122e3SRichard Henderson } 1672fcf5ef2aSThomas Huth 1673372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs, 1674372122e3SRichard Henderson const CPUBreakpoint *bp) 1675372122e3SRichard Henderson { 1676372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1677372122e3SRichard Henderson 1678372122e3SRichard Henderson gen_raise_exception_sync(dc, EXCP_DEBUG); 1679372122e3SRichard Henderson 1680372122e3SRichard Henderson /* 1681372122e3SRichard Henderson * The address covered by the breakpoint must be included in 1682372122e3SRichard Henderson * [tb->pc, tb->pc + tb->size) in order to for it to be 1683372122e3SRichard Henderson * properly cleared -- thus we increment the PC here so that 1684372122e3SRichard Henderson * the logic setting tb->size below does the right thing. 1685372122e3SRichard Henderson */ 1686372122e3SRichard Henderson dc->base.pc_next += 4; 1687372122e3SRichard Henderson return true; 1688372122e3SRichard Henderson } 1689372122e3SRichard Henderson 1690372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) 1691372122e3SRichard Henderson { 1692372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1693372122e3SRichard Henderson CPUMBState *env = cs->env_ptr; 169444d1432bSRichard Henderson uint32_t ir; 1695372122e3SRichard Henderson 1696372122e3SRichard Henderson /* TODO: This should raise an exception, not terminate qemu. */ 1697372122e3SRichard Henderson if (dc->base.pc_next & 3) { 1698372122e3SRichard Henderson cpu_abort(cs, "Microblaze: unaligned PC=%x\n", 1699372122e3SRichard Henderson (uint32_t)dc->base.pc_next); 1700fcf5ef2aSThomas Huth } 1701fcf5ef2aSThomas Huth 1702fcf5ef2aSThomas Huth dc->clear_imm = 1; 170344d1432bSRichard Henderson ir = cpu_ldl_code(env, dc->base.pc_next); 170444d1432bSRichard Henderson if (!decode(dc, ir)) { 170544d1432bSRichard Henderson old_decode(dc, ir); 170644d1432bSRichard Henderson } 1707*20800179SRichard Henderson 1708*20800179SRichard Henderson if (dc->r0) { 1709*20800179SRichard Henderson tcg_temp_free_i32(dc->r0); 1710*20800179SRichard Henderson dc->r0 = NULL; 1711*20800179SRichard Henderson dc->r0_set = false; 1712*20800179SRichard Henderson } 1713*20800179SRichard Henderson 1714d7ecb757SRichard Henderson if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) { 1715fcf5ef2aSThomas Huth dc->tb_flags &= ~IMM_FLAG; 1716d7ecb757SRichard Henderson tcg_gen_discard_i32(cpu_imm); 1717372122e3SRichard Henderson } 1718d4705ae0SRichard Henderson dc->base.pc_next += 4; 1719fcf5ef2aSThomas Huth 1720372122e3SRichard Henderson if (dc->delayed_branch && --dc->delayed_branch == 0) { 1721372122e3SRichard Henderson if (dc->tb_flags & DRTI_FLAG) { 1722fcf5ef2aSThomas Huth do_rti(dc); 1723372122e3SRichard Henderson } 1724372122e3SRichard Henderson if (dc->tb_flags & DRTB_FLAG) { 1725fcf5ef2aSThomas Huth do_rtb(dc); 1726372122e3SRichard Henderson } 1727372122e3SRichard Henderson if (dc->tb_flags & DRTE_FLAG) { 1728fcf5ef2aSThomas Huth do_rte(dc); 1729372122e3SRichard Henderson } 1730fcf5ef2aSThomas Huth /* Clear the delay slot flag. */ 1731fcf5ef2aSThomas Huth dc->tb_flags &= ~D_FLAG; 1732372122e3SRichard Henderson dc->base.is_jmp = DISAS_JUMP; 1733372122e3SRichard Henderson } 1734372122e3SRichard Henderson 1735372122e3SRichard Henderson /* Force an exit if the per-tb cpu state has changed. */ 1736372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) { 1737372122e3SRichard Henderson dc->base.is_jmp = DISAS_UPDATE; 1738372122e3SRichard Henderson tcg_gen_movi_i32(cpu_pc, dc->base.pc_next); 1739372122e3SRichard Henderson } 1740372122e3SRichard Henderson } 1741372122e3SRichard Henderson 1742372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs) 1743372122e3SRichard Henderson { 1744372122e3SRichard Henderson DisasContext *dc = container_of(dcb, DisasContext, base); 1745372122e3SRichard Henderson 1746372122e3SRichard Henderson assert(!dc->abort_at_next_insn); 1747372122e3SRichard Henderson 1748372122e3SRichard Henderson if (dc->base.is_jmp == DISAS_NORETURN) { 1749372122e3SRichard Henderson /* We have already exited the TB. */ 1750372122e3SRichard Henderson return; 1751372122e3SRichard Henderson } 1752372122e3SRichard Henderson 1753372122e3SRichard Henderson t_sync_flags(dc); 1754372122e3SRichard Henderson if (dc->tb_flags & D_FLAG) { 1755372122e3SRichard Henderson sync_jmpstate(dc); 1756372122e3SRichard Henderson dc->jmp = JMP_NOJMP; 1757372122e3SRichard Henderson } 1758372122e3SRichard Henderson 1759372122e3SRichard Henderson switch (dc->base.is_jmp) { 1760372122e3SRichard Henderson case DISAS_TOO_MANY: 1761372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1762372122e3SRichard Henderson gen_goto_tb(dc, 0, dc->base.pc_next); 1763372122e3SRichard Henderson return; 1764372122e3SRichard Henderson 1765372122e3SRichard Henderson case DISAS_UPDATE: 1766372122e3SRichard Henderson assert(dc->jmp == JMP_NOJMP); 1767372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1768372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1769372122e3SRichard Henderson } else { 1770372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1771372122e3SRichard Henderson } 1772372122e3SRichard Henderson return; 1773372122e3SRichard Henderson 1774372122e3SRichard Henderson case DISAS_JUMP: 1775372122e3SRichard Henderson switch (dc->jmp) { 1776372122e3SRichard Henderson case JMP_INDIRECT: 1777372122e3SRichard Henderson { 1778d4705ae0SRichard Henderson TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next); 17790f96e96bSRichard Henderson eval_cond_jmp(dc, cpu_btarget, tmp_pc); 17800f96e96bSRichard Henderson tcg_temp_free_i32(tmp_pc); 1781372122e3SRichard Henderson 1782372122e3SRichard Henderson if (unlikely(cs->singlestep_enabled)) { 1783372122e3SRichard Henderson gen_raise_exception(dc, EXCP_DEBUG); 1784372122e3SRichard Henderson } else { 1785372122e3SRichard Henderson tcg_gen_exit_tb(NULL, 0); 1786372122e3SRichard Henderson } 1787372122e3SRichard Henderson } 1788372122e3SRichard Henderson return; 1789372122e3SRichard Henderson 1790372122e3SRichard Henderson case JMP_DIRECT_CC: 1791372122e3SRichard Henderson { 1792fcf5ef2aSThomas Huth TCGLabel *l1 = gen_new_label(); 17939b158558SRichard Henderson tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1); 1794d4705ae0SRichard Henderson gen_goto_tb(dc, 1, dc->base.pc_next); 1795fcf5ef2aSThomas Huth gen_set_label(l1); 1796372122e3SRichard Henderson } 1797372122e3SRichard Henderson /* fall through */ 1798372122e3SRichard Henderson 1799372122e3SRichard Henderson case JMP_DIRECT: 1800fcf5ef2aSThomas Huth gen_goto_tb(dc, 0, dc->jmp_pc); 1801372122e3SRichard Henderson return; 1802fcf5ef2aSThomas Huth } 1803372122e3SRichard Henderson /* fall through */ 1804fcf5ef2aSThomas Huth 1805a2b80dbdSRichard Henderson default: 1806a2b80dbdSRichard Henderson g_assert_not_reached(); 1807fcf5ef2aSThomas Huth } 1808fcf5ef2aSThomas Huth } 1809fcf5ef2aSThomas Huth 1810372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs) 1811372122e3SRichard Henderson { 1812372122e3SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first)); 1813372122e3SRichard Henderson log_target_disas(cs, dcb->pc_first, dcb->tb->size); 1814fcf5ef2aSThomas Huth } 1815372122e3SRichard Henderson 1816372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = { 1817372122e3SRichard Henderson .init_disas_context = mb_tr_init_disas_context, 1818372122e3SRichard Henderson .tb_start = mb_tr_tb_start, 1819372122e3SRichard Henderson .insn_start = mb_tr_insn_start, 1820372122e3SRichard Henderson .breakpoint_check = mb_tr_breakpoint_check, 1821372122e3SRichard Henderson .translate_insn = mb_tr_translate_insn, 1822372122e3SRichard Henderson .tb_stop = mb_tr_tb_stop, 1823372122e3SRichard Henderson .disas_log = mb_tr_disas_log, 1824372122e3SRichard Henderson }; 1825372122e3SRichard Henderson 1826372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) 1827372122e3SRichard Henderson { 1828372122e3SRichard Henderson DisasContext dc; 1829372122e3SRichard Henderson translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns); 1830fcf5ef2aSThomas Huth } 1831fcf5ef2aSThomas Huth 183290c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) 1833fcf5ef2aSThomas Huth { 1834fcf5ef2aSThomas Huth MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); 1835fcf5ef2aSThomas Huth CPUMBState *env = &cpu->env; 1836fcf5ef2aSThomas Huth int i; 1837fcf5ef2aSThomas Huth 183890c84c56SMarkus Armbruster if (!env) { 1839fcf5ef2aSThomas Huth return; 184090c84c56SMarkus Armbruster } 1841fcf5ef2aSThomas Huth 18420f96e96bSRichard Henderson qemu_fprintf(f, "IN: PC=%x %s\n", 184376e8187dSRichard Henderson env->pc, lookup_symbol(env->pc)); 18446efd5599SRichard Henderson qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " " 1845eb2022b7SRichard Henderson "imm=%x iflags=%x fsr=%x rbtr=%x\n", 184678e9caf2SRichard Henderson env->msr, env->esr, env->ear, 1847eb2022b7SRichard Henderson env->imm, env->iflags, env->fsr, env->btr); 18480f96e96bSRichard Henderson qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n", 1849fcf5ef2aSThomas Huth env->btaken, env->btarget, 18502e5282caSRichard Henderson (env->msr & MSR_UM) ? "user" : "kernel", 18512e5282caSRichard Henderson (env->msr & MSR_UMS) ? "user" : "kernel", 18522e5282caSRichard Henderson (bool)(env->msr & MSR_EIP), 18532e5282caSRichard Henderson (bool)(env->msr & MSR_IE)); 18542ead1b18SJoe Komlodi for (i = 0; i < 12; i++) { 18552ead1b18SJoe Komlodi qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]); 18562ead1b18SJoe Komlodi if ((i + 1) % 4 == 0) { 18572ead1b18SJoe Komlodi qemu_fprintf(f, "\n"); 18582ead1b18SJoe Komlodi } 18592ead1b18SJoe Komlodi } 1860fcf5ef2aSThomas Huth 18612ead1b18SJoe Komlodi /* Registers that aren't modeled are reported as 0 */ 186239db007eSRichard Henderson qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 " 1863af20a93aSRichard Henderson "rtlblo=0 rtlbhi=0\n", env->edr); 18642ead1b18SJoe Komlodi qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr); 1865fcf5ef2aSThomas Huth for (i = 0; i < 32; i++) { 186690c84c56SMarkus Armbruster qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); 1867fcf5ef2aSThomas Huth if ((i + 1) % 4 == 0) 186890c84c56SMarkus Armbruster qemu_fprintf(f, "\n"); 1869fcf5ef2aSThomas Huth } 187090c84c56SMarkus Armbruster qemu_fprintf(f, "\n\n"); 1871fcf5ef2aSThomas Huth } 1872fcf5ef2aSThomas Huth 1873fcf5ef2aSThomas Huth void mb_tcg_init(void) 1874fcf5ef2aSThomas Huth { 1875480d29a8SRichard Henderson #define R(X) { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X } 1876480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X } 1877fcf5ef2aSThomas Huth 1878480d29a8SRichard Henderson static const struct { 1879480d29a8SRichard Henderson TCGv_i32 *var; int ofs; char name[8]; 1880480d29a8SRichard Henderson } i32s[] = { 1881480d29a8SRichard Henderson R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7), 1882480d29a8SRichard Henderson R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15), 1883480d29a8SRichard Henderson R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23), 1884480d29a8SRichard Henderson R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31), 1885480d29a8SRichard Henderson 1886480d29a8SRichard Henderson SP(pc), 1887480d29a8SRichard Henderson SP(msr), 18881074c0fbSRichard Henderson SP(msr_c), 1889480d29a8SRichard Henderson SP(imm), 1890480d29a8SRichard Henderson SP(iflags), 1891480d29a8SRichard Henderson SP(btaken), 1892480d29a8SRichard Henderson SP(btarget), 1893480d29a8SRichard Henderson SP(res_val), 1894480d29a8SRichard Henderson }; 1895480d29a8SRichard Henderson 1896480d29a8SRichard Henderson #undef R 1897480d29a8SRichard Henderson #undef SP 1898480d29a8SRichard Henderson 1899480d29a8SRichard Henderson for (int i = 0; i < ARRAY_SIZE(i32s); ++i) { 1900480d29a8SRichard Henderson *i32s[i].var = 1901480d29a8SRichard Henderson tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name); 1902fcf5ef2aSThomas Huth } 190376e8187dSRichard Henderson 1904480d29a8SRichard Henderson cpu_res_addr = 1905480d29a8SRichard Henderson tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr"); 1906fcf5ef2aSThomas Huth } 1907fcf5ef2aSThomas Huth 1908fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, 1909fcf5ef2aSThomas Huth target_ulong *data) 1910fcf5ef2aSThomas Huth { 191176e8187dSRichard Henderson env->pc = data[0]; 1912fcf5ef2aSThomas Huth } 1913