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