xref: /openbmc/qemu/target/microblaze/translate.c (revision d5aead3df4369f56bf79bcd97a06cd63e4acfee6)
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 
321*d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
322*d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
323*d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
324*d5aead3dSRichard Henderson 
325*d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
326*d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
327*d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
328*d5aead3dSRichard Henderson 
32920800179SRichard Henderson /* No input carry, but output carry. */
33020800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
33120800179SRichard Henderson {
33220800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
33320800179SRichard Henderson 
33420800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
33520800179SRichard Henderson 
33620800179SRichard Henderson     tcg_temp_free_i32(zero);
33720800179SRichard Henderson }
33820800179SRichard Henderson 
33920800179SRichard Henderson /* Input and output carry. */
34020800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
34120800179SRichard Henderson {
34220800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
34320800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
34420800179SRichard Henderson 
34520800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
34620800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
34720800179SRichard Henderson 
34820800179SRichard Henderson     tcg_temp_free_i32(tmp);
34920800179SRichard Henderson     tcg_temp_free_i32(zero);
35020800179SRichard Henderson }
35120800179SRichard Henderson 
35220800179SRichard Henderson /* Input carry, but no output carry. */
35320800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
35420800179SRichard Henderson {
35520800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
35620800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
35720800179SRichard Henderson }
35820800179SRichard Henderson 
35920800179SRichard Henderson DO_TYPEA(add, true, gen_add)
36020800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
36120800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
36220800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
36320800179SRichard Henderson 
36420800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
36520800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
36620800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
36720800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
36820800179SRichard Henderson 
369cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
370cb0a0a4cSRichard Henderson {
371cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
372cb0a0a4cSRichard Henderson }
373cb0a0a4cSRichard Henderson 
374cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
375cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
376cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
377cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
378cb0a0a4cSRichard Henderson 
379081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
380081d8e02SRichard Henderson {
381081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
382081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
383081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
384081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
385081d8e02SRichard Henderson }
386081d8e02SRichard Henderson 
387081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
388081d8e02SRichard Henderson {
389081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
390081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
391081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
392081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
393081d8e02SRichard Henderson }
394081d8e02SRichard Henderson 
395081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
396081d8e02SRichard Henderson {
397081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
398081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
399081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
400081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
401081d8e02SRichard Henderson }
402081d8e02SRichard Henderson 
403081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
404081d8e02SRichard Henderson {
405081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
406081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
407081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
408081d8e02SRichard Henderson 
409081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
410081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
411081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
412081d8e02SRichard Henderson                       imm_w, imm_s);
413081d8e02SRichard Henderson     } else {
414081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
415081d8e02SRichard Henderson     }
416081d8e02SRichard Henderson }
417081d8e02SRichard Henderson 
418081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
419081d8e02SRichard Henderson {
420081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
421081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
422081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
423081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
424081d8e02SRichard Henderson 
425081d8e02SRichard Henderson     if (imm_w < imm_s) {
426081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
427081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
428081d8e02SRichard Henderson                       imm_w, imm_s);
429081d8e02SRichard Henderson     } else {
430081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
431081d8e02SRichard Henderson     }
432081d8e02SRichard Henderson }
433081d8e02SRichard Henderson 
434081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
435081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
436081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
437081d8e02SRichard Henderson 
438081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
439081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
440081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
441081d8e02SRichard Henderson 
442081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
443081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
444081d8e02SRichard Henderson 
44539cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
44639cf3864SRichard Henderson {
44739cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
44839cf3864SRichard Henderson }
44939cf3864SRichard Henderson 
45039cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
45139cf3864SRichard Henderson 
45258b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
45358b48b63SRichard Henderson {
45458b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
45558b48b63SRichard Henderson 
45658b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
45758b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
45858b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
45958b48b63SRichard Henderson     tcg_temp_free_i32(lt);
46058b48b63SRichard Henderson }
46158b48b63SRichard Henderson 
46258b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
46358b48b63SRichard Henderson {
46458b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
46558b48b63SRichard Henderson 
46658b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
46758b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
46858b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
46958b48b63SRichard Henderson     tcg_temp_free_i32(lt);
47058b48b63SRichard Henderson }
47158b48b63SRichard Henderson 
47258b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
47358b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
474a2b0b90eSRichard Henderson 
475*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
476*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
477*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
478*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
479*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
480*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
481*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
482*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
483*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
484*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
485*d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
486*d5aead3dSRichard Henderson 
487*d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
488*d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
489*d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
490*d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
491*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
492*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
493*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
494*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
495*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
496*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
497*d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
498*d5aead3dSRichard Henderson 
499*d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
500*d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
501*d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
502*d5aead3dSRichard Henderson 
503*d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
504*d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
505*d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
506*d5aead3dSRichard Henderson 
507*d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
508b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
509b1354342SRichard Henderson {
510b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
511b1354342SRichard Henderson }
512b1354342SRichard Henderson 
513b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
514b1354342SRichard Henderson {
515b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
516b1354342SRichard Henderson }
517b1354342SRichard Henderson 
518b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
519b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
520b1354342SRichard Henderson 
521e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
522e64b2e5cSRichard Henderson {
523e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
524e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
525e64b2e5cSRichard Henderson     dc->tb_flags |= IMM_FLAG;
526e64b2e5cSRichard Henderson     dc->clear_imm = 0;
527e64b2e5cSRichard Henderson     return true;
528e64b2e5cSRichard Henderson }
529e64b2e5cSRichard Henderson 
53097955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
53197955cebSRichard Henderson {
53297955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
53397955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
53497955cebSRichard Henderson     tcg_temp_free_i32(tmp);
53597955cebSRichard Henderson }
53697955cebSRichard Henderson 
53797955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
53897955cebSRichard Henderson {
53997955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
54097955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
54197955cebSRichard Henderson     tcg_temp_free_i32(tmp);
54297955cebSRichard Henderson }
54397955cebSRichard Henderson 
54497955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
54597955cebSRichard Henderson {
54697955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
54797955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
54897955cebSRichard Henderson     tcg_temp_free_i32(tmp);
54997955cebSRichard Henderson }
55097955cebSRichard Henderson 
55197955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
55297955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
55397955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
55497955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
55597955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
55697955cebSRichard Henderson 
557cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
558cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
559cb0a0a4cSRichard Henderson 
560607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
561607f5767SRichard Henderson {
562607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
563607f5767SRichard Henderson }
564607f5767SRichard Henderson 
565607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
566607f5767SRichard Henderson {
567607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
568607f5767SRichard Henderson }
569607f5767SRichard Henderson 
570607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
571607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
572607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
573607f5767SRichard Henderson 
574a2b0b90eSRichard Henderson /* No input carry, but output carry. */
575a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
576a2b0b90eSRichard Henderson {
577a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
578a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
579a2b0b90eSRichard Henderson }
580a2b0b90eSRichard Henderson 
581a2b0b90eSRichard Henderson /* Input and output carry. */
582a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
583a2b0b90eSRichard Henderson {
584a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
585a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
586a2b0b90eSRichard Henderson 
587a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
588a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
589a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
590a2b0b90eSRichard Henderson 
591a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
592a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
593a2b0b90eSRichard Henderson }
594a2b0b90eSRichard Henderson 
595a2b0b90eSRichard Henderson /* No input or output carry. */
596a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
597a2b0b90eSRichard Henderson {
598a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
599a2b0b90eSRichard Henderson }
600a2b0b90eSRichard Henderson 
601a2b0b90eSRichard Henderson /* Input carry, no output carry. */
602a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
603a2b0b90eSRichard Henderson {
604a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
605a2b0b90eSRichard Henderson 
606a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
607a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
608a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
609a2b0b90eSRichard Henderson 
610a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
611a2b0b90eSRichard Henderson }
612a2b0b90eSRichard Henderson 
613a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
614a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
615a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
616a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
617a2b0b90eSRichard Henderson 
618a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
619a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
620a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
621a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
622a2b0b90eSRichard Henderson 
62339cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
62439cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
62539cf3864SRichard Henderson 
62639cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
62739cf3864SRichard Henderson {
62839cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
62939cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
63039cf3864SRichard Henderson }
63139cf3864SRichard Henderson 
63239cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
63339cf3864SRichard Henderson {
63439cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
63539cf3864SRichard Henderson 
63639cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
63739cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
63839cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
63939cf3864SRichard Henderson 
64039cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
64139cf3864SRichard Henderson }
64239cf3864SRichard Henderson 
64339cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
64439cf3864SRichard Henderson {
64539cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
64639cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
64739cf3864SRichard Henderson }
64839cf3864SRichard Henderson 
64939cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
65039cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
65139cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
65239cf3864SRichard Henderson 
65339cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
65439cf3864SRichard Henderson {
65539cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
65639cf3864SRichard Henderson }
65739cf3864SRichard Henderson 
65839cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
65939cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
66039cf3864SRichard Henderson 
66139cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
66239cf3864SRichard Henderson {
66339cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
66439cf3864SRichard Henderson     trap_userspace(dc, true);
66539cf3864SRichard Henderson     return true;
66639cf3864SRichard Henderson }
66739cf3864SRichard Henderson 
668cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
669cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
670cb0a0a4cSRichard Henderson 
67120800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
67220800179SRichard Henderson {
67320800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
67420800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
67520800179SRichard Henderson         trap_illegal(dc, true);
67620800179SRichard Henderson         return true;
67720800179SRichard Henderson     }
67820800179SRichard Henderson     /*
67920800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
68020800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
68120800179SRichard Henderson      */
68220800179SRichard Henderson     return false;
683fcf5ef2aSThomas Huth }
684fcf5ef2aSThomas Huth 
6851074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
686fcf5ef2aSThomas Huth {
6871074c0fbSRichard Henderson     TCGv_i32 t;
6881074c0fbSRichard Henderson 
6891074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
6901074c0fbSRichard Henderson     t = tcg_temp_new_i32();
6911074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
6921074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
6931074c0fbSRichard Henderson     tcg_temp_free_i32(t);
694fcf5ef2aSThomas Huth }
695fcf5ef2aSThomas Huth 
6961074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v)
697fcf5ef2aSThomas Huth {
698fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
6991074c0fbSRichard Henderson 
7001074c0fbSRichard Henderson     /* Install MSR_C.  */
7011074c0fbSRichard Henderson     tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
7021074c0fbSRichard Henderson 
7031074c0fbSRichard Henderson     /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
7041074c0fbSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
705fcf5ef2aSThomas Huth }
706fcf5ef2aSThomas Huth 
707fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc)
708fcf5ef2aSThomas Huth {
709fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
710cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
7112023e9a3SEdgar E. Iglesias     unsigned int sr, rn;
712f0f7e7f7SEdgar E. Iglesias     bool to, clrset, extended = false;
713fcf5ef2aSThomas Huth 
7142023e9a3SEdgar E. Iglesias     sr = extract32(dc->imm, 0, 14);
7152023e9a3SEdgar E. Iglesias     to = extract32(dc->imm, 14, 1);
7162023e9a3SEdgar E. Iglesias     clrset = extract32(dc->imm, 15, 1) == 0;
717fcf5ef2aSThomas Huth     dc->type_b = 1;
7182023e9a3SEdgar E. Iglesias     if (to) {
719fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
720f0f7e7f7SEdgar E. Iglesias     }
721f0f7e7f7SEdgar E. Iglesias 
722f0f7e7f7SEdgar E. Iglesias     /* Extended MSRs are only available if addr_size > 32.  */
723f0f7e7f7SEdgar E. Iglesias     if (dc->cpu->cfg.addr_size > 32) {
724f0f7e7f7SEdgar E. Iglesias         /* The E-bit is encoded differently for To/From MSR.  */
725f0f7e7f7SEdgar E. Iglesias         static const unsigned int e_bit[] = { 19, 24 };
726f0f7e7f7SEdgar E. Iglesias 
727f0f7e7f7SEdgar E. Iglesias         extended = extract32(dc->imm, e_bit[to], 1);
7282023e9a3SEdgar E. Iglesias     }
729fcf5ef2aSThomas Huth 
730fcf5ef2aSThomas Huth     /* msrclr and msrset.  */
7312023e9a3SEdgar E. Iglesias     if (clrset) {
7322023e9a3SEdgar E. Iglesias         bool clr = extract32(dc->ir, 16, 1);
733fcf5ef2aSThomas Huth 
73456837509SEdgar E. Iglesias         if (!dc->cpu->cfg.use_msr_instr) {
735fcf5ef2aSThomas Huth             /* nop??? */
736fcf5ef2aSThomas Huth             return;
737fcf5ef2aSThomas Huth         }
738fcf5ef2aSThomas Huth 
739bdfc1e88SEdgar E. Iglesias         if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
740fcf5ef2aSThomas Huth             return;
741fcf5ef2aSThomas Huth         }
742fcf5ef2aSThomas Huth 
743fcf5ef2aSThomas Huth         if (dc->rd)
744fcf5ef2aSThomas Huth             msr_read(dc, cpu_R[dc->rd]);
745fcf5ef2aSThomas Huth 
746cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
747cfeea807SEdgar E. Iglesias         t1 = tcg_temp_new_i32();
748fcf5ef2aSThomas Huth         msr_read(dc, t0);
749cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
750fcf5ef2aSThomas Huth 
751fcf5ef2aSThomas Huth         if (clr) {
752cfeea807SEdgar E. Iglesias             tcg_gen_not_i32(t1, t1);
753cfeea807SEdgar E. Iglesias             tcg_gen_and_i32(t0, t0, t1);
754fcf5ef2aSThomas Huth         } else
755cfeea807SEdgar E. Iglesias             tcg_gen_or_i32(t0, t0, t1);
756fcf5ef2aSThomas Huth         msr_write(dc, t0);
757cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
758cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t1);
759d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
760d4705ae0SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
761fcf5ef2aSThomas Huth         return;
762fcf5ef2aSThomas Huth     }
763fcf5ef2aSThomas Huth 
764bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, to)) {
765fcf5ef2aSThomas Huth         return;
766fcf5ef2aSThomas Huth     }
767fcf5ef2aSThomas Huth 
768fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
769fcf5ef2aSThomas Huth     /* Catch read/writes to the mmu block.  */
770fcf5ef2aSThomas Huth     if ((sr & ~0xff) == 0x1000) {
771f0f7e7f7SEdgar E. Iglesias         TCGv_i32 tmp_ext = tcg_const_i32(extended);
77205a9a651SEdgar E. Iglesias         TCGv_i32 tmp_sr;
77305a9a651SEdgar E. Iglesias 
774fcf5ef2aSThomas Huth         sr &= 7;
77505a9a651SEdgar E. Iglesias         tmp_sr = tcg_const_i32(sr);
77605a9a651SEdgar E. Iglesias         if (to) {
777f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
77805a9a651SEdgar E. Iglesias         } else {
779f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
78005a9a651SEdgar E. Iglesias         }
78105a9a651SEdgar E. Iglesias         tcg_temp_free_i32(tmp_sr);
782f0f7e7f7SEdgar E. Iglesias         tcg_temp_free_i32(tmp_ext);
783fcf5ef2aSThomas Huth         return;
784fcf5ef2aSThomas Huth     }
785fcf5ef2aSThomas Huth #endif
786fcf5ef2aSThomas Huth 
787fcf5ef2aSThomas Huth     if (to) {
788fcf5ef2aSThomas Huth         switch (sr) {
789aa28e6d4SRichard Henderson             case SR_PC:
790fcf5ef2aSThomas Huth                 break;
791aa28e6d4SRichard Henderson             case SR_MSR:
792fcf5ef2aSThomas Huth                 msr_write(dc, cpu_R[dc->ra]);
793fcf5ef2aSThomas Huth                 break;
794351527b7SEdgar E. Iglesias             case SR_EAR:
795dbdb77c4SRichard Henderson                 {
796dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
797dbdb77c4SRichard Henderson                     tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]);
798dbdb77c4SRichard Henderson                     tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear));
799dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
800dbdb77c4SRichard Henderson                 }
801aa28e6d4SRichard Henderson                 break;
802351527b7SEdgar E. Iglesias             case SR_ESR:
80341ba37c4SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
80441ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
805aa28e6d4SRichard Henderson                 break;
806ab6dd380SEdgar E. Iglesias             case SR_FSR:
80786017ccfSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
80886017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
809aa28e6d4SRichard Henderson                 break;
810aa28e6d4SRichard Henderson             case SR_BTR:
811ccf628b7SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
812ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
813aa28e6d4SRichard Henderson                 break;
814aa28e6d4SRichard Henderson             case SR_EDR:
81539db007eSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
81639db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
817fcf5ef2aSThomas Huth                 break;
818fcf5ef2aSThomas Huth             case 0x800:
819cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
820cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
821fcf5ef2aSThomas Huth                 break;
822fcf5ef2aSThomas Huth             case 0x802:
823cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
824cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
825fcf5ef2aSThomas Huth                 break;
826fcf5ef2aSThomas Huth             default:
827fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
828fcf5ef2aSThomas Huth                 break;
829fcf5ef2aSThomas Huth         }
830fcf5ef2aSThomas Huth     } else {
831fcf5ef2aSThomas Huth         switch (sr) {
832aa28e6d4SRichard Henderson             case SR_PC:
833d4705ae0SRichard Henderson                 tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
834fcf5ef2aSThomas Huth                 break;
835aa28e6d4SRichard Henderson             case SR_MSR:
836fcf5ef2aSThomas Huth                 msr_read(dc, cpu_R[dc->rd]);
837fcf5ef2aSThomas Huth                 break;
838351527b7SEdgar E. Iglesias             case SR_EAR:
839dbdb77c4SRichard Henderson                 {
840dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
841dbdb77c4SRichard Henderson                     tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
842a1b48e3aSEdgar E. Iglesias                     if (extended) {
843dbdb77c4SRichard Henderson                         tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64);
844aa28e6d4SRichard Henderson                     } else {
845dbdb77c4SRichard Henderson                         tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64);
846dbdb77c4SRichard Henderson                     }
847dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
848a1b48e3aSEdgar E. Iglesias                 }
849aa28e6d4SRichard Henderson                 break;
850351527b7SEdgar E. Iglesias             case SR_ESR:
85141ba37c4SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
85241ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
853aa28e6d4SRichard Henderson                 break;
854351527b7SEdgar E. Iglesias             case SR_FSR:
85586017ccfSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
85686017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
857aa28e6d4SRichard Henderson                 break;
858351527b7SEdgar E. Iglesias             case SR_BTR:
859ccf628b7SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
860ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
861aa28e6d4SRichard Henderson                 break;
8627cdae31dSTong Ho             case SR_EDR:
86339db007eSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
86439db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
865fcf5ef2aSThomas Huth                 break;
866fcf5ef2aSThomas Huth             case 0x800:
867cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
868cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
869fcf5ef2aSThomas Huth                 break;
870fcf5ef2aSThomas Huth             case 0x802:
871cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
872cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
873fcf5ef2aSThomas Huth                 break;
874351527b7SEdgar E. Iglesias             case 0x2000 ... 0x200c:
875fcf5ef2aSThomas Huth                 rn = sr & 0xf;
876cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
877fcf5ef2aSThomas Huth                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
878fcf5ef2aSThomas Huth                 break;
879fcf5ef2aSThomas Huth             default:
880fcf5ef2aSThomas Huth                 cpu_abort(cs, "unknown mfs reg %x\n", sr);
881fcf5ef2aSThomas Huth                 break;
882fcf5ef2aSThomas Huth         }
883fcf5ef2aSThomas Huth     }
884fcf5ef2aSThomas Huth 
885fcf5ef2aSThomas Huth     if (dc->rd == 0) {
886cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[0], 0);
887fcf5ef2aSThomas Huth     }
888fcf5ef2aSThomas Huth }
889fcf5ef2aSThomas Huth 
890fcf5ef2aSThomas Huth static inline void sync_jmpstate(DisasContext *dc)
891fcf5ef2aSThomas Huth {
892fcf5ef2aSThomas Huth     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
893fcf5ef2aSThomas Huth         if (dc->jmp == JMP_DIRECT) {
8949b158558SRichard Henderson             tcg_gen_movi_i32(cpu_btaken, 1);
895fcf5ef2aSThomas Huth         }
896fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
8970f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
898fcf5ef2aSThomas Huth     }
899fcf5ef2aSThomas Huth }
900fcf5ef2aSThomas Huth 
901d248e1beSEdgar E. Iglesias static inline void compute_ldst_addr(DisasContext *dc, bool ea, TCGv t)
902fcf5ef2aSThomas Huth {
9030e9033c8SEdgar E. Iglesias     /* Should be set to true if r1 is used by loadstores.  */
9040e9033c8SEdgar E. Iglesias     bool stackprot = false;
905403322eaSEdgar E. Iglesias     TCGv_i32 t32;
906fcf5ef2aSThomas Huth 
907fcf5ef2aSThomas Huth     /* All load/stores use ra.  */
908fcf5ef2aSThomas Huth     if (dc->ra == 1 && dc->cpu->cfg.stackprot) {
9090e9033c8SEdgar E. Iglesias         stackprot = true;
910fcf5ef2aSThomas Huth     }
911fcf5ef2aSThomas Huth 
912fcf5ef2aSThomas Huth     /* Treat the common cases first.  */
913fcf5ef2aSThomas Huth     if (!dc->type_b) {
914d248e1beSEdgar E. Iglesias         if (ea) {
915d248e1beSEdgar E. Iglesias             int addr_size = dc->cpu->cfg.addr_size;
916d248e1beSEdgar E. Iglesias 
917d248e1beSEdgar E. Iglesias             if (addr_size == 32) {
918d248e1beSEdgar E. Iglesias                 tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
919d248e1beSEdgar E. Iglesias                 return;
920d248e1beSEdgar E. Iglesias             }
921d248e1beSEdgar E. Iglesias 
922d248e1beSEdgar E. Iglesias             tcg_gen_concat_i32_i64(t, cpu_R[dc->rb], cpu_R[dc->ra]);
923d248e1beSEdgar E. Iglesias             if (addr_size < 64) {
924d248e1beSEdgar E. Iglesias                 /* Mask off out of range bits.  */
925d248e1beSEdgar E. Iglesias                 tcg_gen_andi_i64(t, t, MAKE_64BIT_MASK(0, addr_size));
926d248e1beSEdgar E. Iglesias             }
927d248e1beSEdgar E. Iglesias             return;
928d248e1beSEdgar E. Iglesias         }
929d248e1beSEdgar E. Iglesias 
9300dc4af5cSEdgar E. Iglesias         /* If any of the regs is r0, set t to the value of the other reg.  */
931fcf5ef2aSThomas Huth         if (dc->ra == 0) {
932403322eaSEdgar E. Iglesias             tcg_gen_extu_i32_tl(t, cpu_R[dc->rb]);
9330dc4af5cSEdgar E. Iglesias             return;
934fcf5ef2aSThomas Huth         } else if (dc->rb == 0) {
935403322eaSEdgar E. Iglesias             tcg_gen_extu_i32_tl(t, cpu_R[dc->ra]);
9360dc4af5cSEdgar E. Iglesias             return;
937fcf5ef2aSThomas Huth         }
938fcf5ef2aSThomas Huth 
939fcf5ef2aSThomas Huth         if (dc->rb == 1 && dc->cpu->cfg.stackprot) {
9400e9033c8SEdgar E. Iglesias             stackprot = true;
941fcf5ef2aSThomas Huth         }
942fcf5ef2aSThomas Huth 
943403322eaSEdgar E. Iglesias         t32 = tcg_temp_new_i32();
944403322eaSEdgar E. Iglesias         tcg_gen_add_i32(t32, cpu_R[dc->ra], cpu_R[dc->rb]);
945403322eaSEdgar E. Iglesias         tcg_gen_extu_i32_tl(t, t32);
946403322eaSEdgar E. Iglesias         tcg_temp_free_i32(t32);
947fcf5ef2aSThomas Huth 
948fcf5ef2aSThomas Huth         if (stackprot) {
9490a87e691SEdgar E. Iglesias             gen_helper_stackprot(cpu_env, t);
950fcf5ef2aSThomas Huth         }
9510dc4af5cSEdgar E. Iglesias         return;
952fcf5ef2aSThomas Huth     }
953fcf5ef2aSThomas Huth     /* Immediate.  */
954403322eaSEdgar E. Iglesias     t32 = tcg_temp_new_i32();
955d7ecb757SRichard Henderson     tcg_gen_addi_i32(t32, cpu_R[dc->ra], dec_alu_typeb_imm(dc));
956403322eaSEdgar E. Iglesias     tcg_gen_extu_i32_tl(t, t32);
957403322eaSEdgar E. Iglesias     tcg_temp_free_i32(t32);
958fcf5ef2aSThomas Huth 
959fcf5ef2aSThomas Huth     if (stackprot) {
9600a87e691SEdgar E. Iglesias         gen_helper_stackprot(cpu_env, t);
961fcf5ef2aSThomas Huth     }
9620dc4af5cSEdgar E. Iglesias     return;
963fcf5ef2aSThomas Huth }
964fcf5ef2aSThomas Huth 
965fcf5ef2aSThomas Huth static void dec_load(DisasContext *dc)
966fcf5ef2aSThomas Huth {
967403322eaSEdgar E. Iglesias     TCGv_i32 v;
968403322eaSEdgar E. Iglesias     TCGv addr;
9698534063aSEdgar E. Iglesias     unsigned int size;
970d248e1beSEdgar E. Iglesias     bool rev = false, ex = false, ea = false;
971d248e1beSEdgar E. Iglesias     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
97214776ab5STony Nguyen     MemOp mop;
973fcf5ef2aSThomas Huth 
974fcf5ef2aSThomas Huth     mop = dc->opcode & 3;
975fcf5ef2aSThomas Huth     size = 1 << mop;
976fcf5ef2aSThomas Huth     if (!dc->type_b) {
977d248e1beSEdgar E. Iglesias         ea = extract32(dc->ir, 7, 1);
9788534063aSEdgar E. Iglesias         rev = extract32(dc->ir, 9, 1);
9798534063aSEdgar E. Iglesias         ex = extract32(dc->ir, 10, 1);
980fcf5ef2aSThomas Huth     }
981fcf5ef2aSThomas Huth     mop |= MO_TE;
982fcf5ef2aSThomas Huth     if (rev) {
983fcf5ef2aSThomas Huth         mop ^= MO_BSWAP;
984fcf5ef2aSThomas Huth     }
985fcf5ef2aSThomas Huth 
9869ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, size > 4)) {
987fcf5ef2aSThomas Huth         return;
988fcf5ef2aSThomas Huth     }
989fcf5ef2aSThomas Huth 
990d248e1beSEdgar E. Iglesias     if (trap_userspace(dc, ea)) {
991d248e1beSEdgar E. Iglesias         return;
992d248e1beSEdgar E. Iglesias     }
993d248e1beSEdgar E. Iglesias 
994fcf5ef2aSThomas Huth     t_sync_flags(dc);
995403322eaSEdgar E. Iglesias     addr = tcg_temp_new();
996d248e1beSEdgar E. Iglesias     compute_ldst_addr(dc, ea, addr);
997d248e1beSEdgar E. Iglesias     /* Extended addressing bypasses the MMU.  */
998d248e1beSEdgar E. Iglesias     mem_index = ea ? MMU_NOMMU_IDX : mem_index;
999fcf5ef2aSThomas Huth 
1000fcf5ef2aSThomas Huth     /*
1001fcf5ef2aSThomas Huth      * When doing reverse accesses we need to do two things.
1002fcf5ef2aSThomas Huth      *
1003fcf5ef2aSThomas Huth      * 1. Reverse the address wrt endianness.
1004fcf5ef2aSThomas Huth      * 2. Byteswap the data lanes on the way back into the CPU core.
1005fcf5ef2aSThomas Huth      */
1006fcf5ef2aSThomas Huth     if (rev && size != 4) {
1007fcf5ef2aSThomas Huth         /* Endian reverse the address. t is addr.  */
1008fcf5ef2aSThomas Huth         switch (size) {
1009fcf5ef2aSThomas Huth             case 1:
1010fcf5ef2aSThomas Huth             {
1011a6338015SEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 3);
1012fcf5ef2aSThomas Huth                 break;
1013fcf5ef2aSThomas Huth             }
1014fcf5ef2aSThomas Huth 
1015fcf5ef2aSThomas Huth             case 2:
1016fcf5ef2aSThomas Huth                 /* 00 -> 10
1017fcf5ef2aSThomas Huth                    10 -> 00.  */
1018403322eaSEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 2);
1019fcf5ef2aSThomas Huth                 break;
1020fcf5ef2aSThomas Huth             default:
1021fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
1022fcf5ef2aSThomas Huth                 break;
1023fcf5ef2aSThomas Huth         }
1024fcf5ef2aSThomas Huth     }
1025fcf5ef2aSThomas Huth 
1026fcf5ef2aSThomas Huth     /* lwx does not throw unaligned access errors, so force alignment */
1027fcf5ef2aSThomas Huth     if (ex) {
1028403322eaSEdgar E. Iglesias         tcg_gen_andi_tl(addr, addr, ~3);
1029fcf5ef2aSThomas Huth     }
1030fcf5ef2aSThomas Huth 
1031fcf5ef2aSThomas Huth     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
1032fcf5ef2aSThomas Huth     sync_jmpstate(dc);
1033fcf5ef2aSThomas Huth 
1034fcf5ef2aSThomas Huth     /* Verify alignment if needed.  */
1035fcf5ef2aSThomas Huth     /*
1036fcf5ef2aSThomas Huth      * Microblaze gives MMU faults priority over faults due to
1037fcf5ef2aSThomas Huth      * unaligned addresses. That's why we speculatively do the load
1038fcf5ef2aSThomas Huth      * into v. If the load succeeds, we verify alignment of the
1039fcf5ef2aSThomas Huth      * address and if that succeeds we write into the destination reg.
1040fcf5ef2aSThomas Huth      */
1041cfeea807SEdgar E. Iglesias     v = tcg_temp_new_i32();
1042d248e1beSEdgar E. Iglesias     tcg_gen_qemu_ld_i32(v, addr, mem_index, mop);
1043fcf5ef2aSThomas Huth 
10441507e5f6SEdgar E. Iglesias     if (dc->cpu->cfg.unaligned_exceptions && size > 1) {
1045a6338015SEdgar E. Iglesias         TCGv_i32 t0 = tcg_const_i32(0);
1046a6338015SEdgar E. Iglesias         TCGv_i32 treg = tcg_const_i32(dc->rd);
1047a6338015SEdgar E. Iglesias         TCGv_i32 tsize = tcg_const_i32(size - 1);
1048a6338015SEdgar E. Iglesias 
1049d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1050a6338015SEdgar E. Iglesias         gen_helper_memalign(cpu_env, addr, treg, t0, tsize);
1051a6338015SEdgar E. Iglesias 
1052a6338015SEdgar E. Iglesias         tcg_temp_free_i32(t0);
1053a6338015SEdgar E. Iglesias         tcg_temp_free_i32(treg);
1054a6338015SEdgar E. Iglesias         tcg_temp_free_i32(tsize);
1055fcf5ef2aSThomas Huth     }
1056fcf5ef2aSThomas Huth 
1057fcf5ef2aSThomas Huth     if (ex) {
10589b158558SRichard Henderson         tcg_gen_mov_tl(cpu_res_addr, addr);
10599b158558SRichard Henderson         tcg_gen_mov_i32(cpu_res_val, v);
1060fcf5ef2aSThomas Huth     }
1061fcf5ef2aSThomas Huth     if (dc->rd) {
1062cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(cpu_R[dc->rd], v);
1063fcf5ef2aSThomas Huth     }
1064cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(v);
1065fcf5ef2aSThomas Huth 
1066fcf5ef2aSThomas Huth     if (ex) { /* lwx */
1067fcf5ef2aSThomas Huth         /* no support for AXI exclusive so always clear C */
10681074c0fbSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, 0);
1069fcf5ef2aSThomas Huth     }
1070fcf5ef2aSThomas Huth 
1071403322eaSEdgar E. Iglesias     tcg_temp_free(addr);
1072fcf5ef2aSThomas Huth }
1073fcf5ef2aSThomas Huth 
1074fcf5ef2aSThomas Huth static void dec_store(DisasContext *dc)
1075fcf5ef2aSThomas Huth {
1076403322eaSEdgar E. Iglesias     TCGv addr;
1077fcf5ef2aSThomas Huth     TCGLabel *swx_skip = NULL;
1078b51b3d43SEdgar E. Iglesias     unsigned int size;
1079d248e1beSEdgar E. Iglesias     bool rev = false, ex = false, ea = false;
1080d248e1beSEdgar E. Iglesias     int mem_index = cpu_mmu_index(&dc->cpu->env, false);
108114776ab5STony Nguyen     MemOp mop;
1082fcf5ef2aSThomas Huth 
1083fcf5ef2aSThomas Huth     mop = dc->opcode & 3;
1084fcf5ef2aSThomas Huth     size = 1 << mop;
1085fcf5ef2aSThomas Huth     if (!dc->type_b) {
1086d248e1beSEdgar E. Iglesias         ea = extract32(dc->ir, 7, 1);
1087b51b3d43SEdgar E. Iglesias         rev = extract32(dc->ir, 9, 1);
1088b51b3d43SEdgar E. Iglesias         ex = extract32(dc->ir, 10, 1);
1089fcf5ef2aSThomas Huth     }
1090fcf5ef2aSThomas Huth     mop |= MO_TE;
1091fcf5ef2aSThomas Huth     if (rev) {
1092fcf5ef2aSThomas Huth         mop ^= MO_BSWAP;
1093fcf5ef2aSThomas Huth     }
1094fcf5ef2aSThomas Huth 
10959ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, size > 4)) {
1096fcf5ef2aSThomas Huth         return;
1097fcf5ef2aSThomas Huth     }
1098fcf5ef2aSThomas Huth 
1099d248e1beSEdgar E. Iglesias     trap_userspace(dc, ea);
1100d248e1beSEdgar E. Iglesias 
1101fcf5ef2aSThomas Huth     t_sync_flags(dc);
1102fcf5ef2aSThomas Huth     /* If we get a fault on a dslot, the jmpstate better be in sync.  */
1103fcf5ef2aSThomas Huth     sync_jmpstate(dc);
11040dc4af5cSEdgar E. Iglesias     /* SWX needs a temp_local.  */
1105403322eaSEdgar E. Iglesias     addr = ex ? tcg_temp_local_new() : tcg_temp_new();
1106d248e1beSEdgar E. Iglesias     compute_ldst_addr(dc, ea, addr);
1107d248e1beSEdgar E. Iglesias     /* Extended addressing bypasses the MMU.  */
1108d248e1beSEdgar E. Iglesias     mem_index = ea ? MMU_NOMMU_IDX : mem_index;
1109fcf5ef2aSThomas Huth 
1110fcf5ef2aSThomas Huth     if (ex) { /* swx */
1111cfeea807SEdgar E. Iglesias         TCGv_i32 tval;
1112fcf5ef2aSThomas Huth 
1113fcf5ef2aSThomas Huth         /* swx does not throw unaligned access errors, so force alignment */
1114403322eaSEdgar E. Iglesias         tcg_gen_andi_tl(addr, addr, ~3);
1115fcf5ef2aSThomas Huth 
11161074c0fbSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, 1);
1117fcf5ef2aSThomas Huth         swx_skip = gen_new_label();
11189b158558SRichard Henderson         tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_skip);
1119fcf5ef2aSThomas Huth 
1120071cdc67SEdgar E. Iglesias         /*
1121071cdc67SEdgar E. Iglesias          * Compare the value loaded at lwx with current contents of
1122071cdc67SEdgar E. Iglesias          * the reserved location.
1123071cdc67SEdgar E. Iglesias          */
1124cfeea807SEdgar E. Iglesias         tval = tcg_temp_new_i32();
1125071cdc67SEdgar E. Iglesias 
11269b158558SRichard Henderson         tcg_gen_atomic_cmpxchg_i32(tval, addr, cpu_res_val,
1127071cdc67SEdgar E. Iglesias                                    cpu_R[dc->rd], mem_index,
1128071cdc67SEdgar E. Iglesias                                    mop);
1129071cdc67SEdgar E. Iglesias 
11309b158558SRichard Henderson         tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_skip);
11311074c0fbSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, 0);
1132cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(tval);
1133fcf5ef2aSThomas Huth     }
1134fcf5ef2aSThomas Huth 
1135fcf5ef2aSThomas Huth     if (rev && size != 4) {
1136fcf5ef2aSThomas Huth         /* Endian reverse the address. t is addr.  */
1137fcf5ef2aSThomas Huth         switch (size) {
1138fcf5ef2aSThomas Huth             case 1:
1139fcf5ef2aSThomas Huth             {
1140a6338015SEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 3);
1141fcf5ef2aSThomas Huth                 break;
1142fcf5ef2aSThomas Huth             }
1143fcf5ef2aSThomas Huth 
1144fcf5ef2aSThomas Huth             case 2:
1145fcf5ef2aSThomas Huth                 /* 00 -> 10
1146fcf5ef2aSThomas Huth                    10 -> 00.  */
1147fcf5ef2aSThomas Huth                 /* Force addr into the temp.  */
1148403322eaSEdgar E. Iglesias                 tcg_gen_xori_tl(addr, addr, 2);
1149fcf5ef2aSThomas Huth                 break;
1150fcf5ef2aSThomas Huth             default:
1151fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "Invalid reverse size\n");
1152fcf5ef2aSThomas Huth                 break;
1153fcf5ef2aSThomas Huth         }
1154fcf5ef2aSThomas Huth     }
1155071cdc67SEdgar E. Iglesias 
1156071cdc67SEdgar E. Iglesias     if (!ex) {
1157d248e1beSEdgar E. Iglesias         tcg_gen_qemu_st_i32(cpu_R[dc->rd], addr, mem_index, mop);
1158071cdc67SEdgar E. Iglesias     }
1159fcf5ef2aSThomas Huth 
1160fcf5ef2aSThomas Huth     /* Verify alignment if needed.  */
11611507e5f6SEdgar E. Iglesias     if (dc->cpu->cfg.unaligned_exceptions && size > 1) {
1162a6338015SEdgar E. Iglesias         TCGv_i32 t1 = tcg_const_i32(1);
1163a6338015SEdgar E. Iglesias         TCGv_i32 treg = tcg_const_i32(dc->rd);
1164a6338015SEdgar E. Iglesias         TCGv_i32 tsize = tcg_const_i32(size - 1);
1165a6338015SEdgar E. Iglesias 
1166d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1167fcf5ef2aSThomas Huth         /* FIXME: if the alignment is wrong, we should restore the value
1168fcf5ef2aSThomas Huth          *        in memory. One possible way to achieve this is to probe
1169fcf5ef2aSThomas Huth          *        the MMU prior to the memaccess, thay way we could put
1170fcf5ef2aSThomas Huth          *        the alignment checks in between the probe and the mem
1171fcf5ef2aSThomas Huth          *        access.
1172fcf5ef2aSThomas Huth          */
1173a6338015SEdgar E. Iglesias         gen_helper_memalign(cpu_env, addr, treg, t1, tsize);
1174a6338015SEdgar E. Iglesias 
1175a6338015SEdgar E. Iglesias         tcg_temp_free_i32(t1);
1176a6338015SEdgar E. Iglesias         tcg_temp_free_i32(treg);
1177a6338015SEdgar E. Iglesias         tcg_temp_free_i32(tsize);
1178fcf5ef2aSThomas Huth     }
1179fcf5ef2aSThomas Huth 
1180fcf5ef2aSThomas Huth     if (ex) {
1181fcf5ef2aSThomas Huth         gen_set_label(swx_skip);
1182fcf5ef2aSThomas Huth     }
1183fcf5ef2aSThomas Huth 
1184403322eaSEdgar E. Iglesias     tcg_temp_free(addr);
1185fcf5ef2aSThomas Huth }
1186fcf5ef2aSThomas Huth 
1187fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc,
11889e6e1828SEdgar E. Iglesias                            TCGv_i32 d, TCGv_i32 a)
1189fcf5ef2aSThomas Huth {
1190d89b86e9SEdgar E. Iglesias     static const int mb_to_tcg_cc[] = {
1191d89b86e9SEdgar E. Iglesias         [CC_EQ] = TCG_COND_EQ,
1192d89b86e9SEdgar E. Iglesias         [CC_NE] = TCG_COND_NE,
1193d89b86e9SEdgar E. Iglesias         [CC_LT] = TCG_COND_LT,
1194d89b86e9SEdgar E. Iglesias         [CC_LE] = TCG_COND_LE,
1195d89b86e9SEdgar E. Iglesias         [CC_GE] = TCG_COND_GE,
1196d89b86e9SEdgar E. Iglesias         [CC_GT] = TCG_COND_GT,
1197d89b86e9SEdgar E. Iglesias     };
1198d89b86e9SEdgar E. Iglesias 
1199fcf5ef2aSThomas Huth     switch (cc) {
1200fcf5ef2aSThomas Huth     case CC_EQ:
1201fcf5ef2aSThomas Huth     case CC_NE:
1202fcf5ef2aSThomas Huth     case CC_LT:
1203fcf5ef2aSThomas Huth     case CC_LE:
1204fcf5ef2aSThomas Huth     case CC_GE:
1205fcf5ef2aSThomas Huth     case CC_GT:
12069e6e1828SEdgar E. Iglesias         tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
1207fcf5ef2aSThomas Huth         break;
1208fcf5ef2aSThomas Huth     default:
1209fcf5ef2aSThomas Huth         cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
1210fcf5ef2aSThomas Huth         break;
1211fcf5ef2aSThomas Huth     }
1212fcf5ef2aSThomas Huth }
1213fcf5ef2aSThomas Huth 
12140f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false)
1215fcf5ef2aSThomas Huth {
12160f96e96bSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
1217e956caf2SEdgar E. Iglesias 
12180f96e96bSRichard Henderson     tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc,
12199b158558SRichard Henderson                         cpu_btaken, zero,
1220e956caf2SEdgar E. Iglesias                         pc_true, pc_false);
1221e956caf2SEdgar E. Iglesias 
12220f96e96bSRichard Henderson     tcg_temp_free_i32(zero);
1223fcf5ef2aSThomas Huth }
1224fcf5ef2aSThomas Huth 
1225f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc)
1226f91c60f0SEdgar E. Iglesias {
1227f91c60f0SEdgar E. Iglesias         TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG));
1228f91c60f0SEdgar E. Iglesias 
1229f91c60f0SEdgar E. Iglesias         dc->delayed_branch = 2;
1230f91c60f0SEdgar E. Iglesias         dc->tb_flags |= D_FLAG;
1231f91c60f0SEdgar E. Iglesias 
1232f91c60f0SEdgar E. Iglesias         tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm));
1233f91c60f0SEdgar E. Iglesias         tcg_temp_free_i32(tmp);
1234f91c60f0SEdgar E. Iglesias }
1235f91c60f0SEdgar E. Iglesias 
1236fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc)
1237fcf5ef2aSThomas Huth {
1238fcf5ef2aSThomas Huth     unsigned int cc;
1239fcf5ef2aSThomas Huth     unsigned int dslot;
1240fcf5ef2aSThomas Huth 
1241fcf5ef2aSThomas Huth     cc = EXTRACT_FIELD(dc->ir, 21, 23);
1242fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 25);
1243fcf5ef2aSThomas Huth 
1244fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1245fcf5ef2aSThomas Huth     if (dslot) {
1246f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1247fcf5ef2aSThomas Huth     }
1248fcf5ef2aSThomas Huth 
1249d7ecb757SRichard Henderson     if (dc->type_b) {
1250fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT_CC;
1251d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1252d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1253fcf5ef2aSThomas Huth     } else {
1254fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
1255d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1256fcf5ef2aSThomas Huth     }
12579b158558SRichard Henderson     eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]);
1258fcf5ef2aSThomas Huth }
1259fcf5ef2aSThomas Huth 
1260fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc)
1261fcf5ef2aSThomas Huth {
1262fcf5ef2aSThomas Huth     unsigned int dslot, link, abs, mbar;
1263fcf5ef2aSThomas Huth 
1264fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 20);
1265fcf5ef2aSThomas Huth     abs = dc->ir & (1 << 19);
1266fcf5ef2aSThomas Huth     link = dc->ir & (1 << 18);
1267fcf5ef2aSThomas Huth 
1268fcf5ef2aSThomas Huth     /* Memory barrier.  */
1269fcf5ef2aSThomas Huth     mbar = (dc->ir >> 16) & 31;
1270fcf5ef2aSThomas Huth     if (mbar == 2 && dc->imm == 4) {
1271badcbf9dSEdgar E. Iglesias         uint16_t mbar_imm = dc->rd;
1272badcbf9dSEdgar E. Iglesias 
12733f172744SEdgar E. Iglesias         /* Data access memory barrier.  */
12743f172744SEdgar E. Iglesias         if ((mbar_imm & 2) == 0) {
12753f172744SEdgar E. Iglesias             tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
12763f172744SEdgar E. Iglesias         }
12773f172744SEdgar E. Iglesias 
1278fcf5ef2aSThomas Huth         /* mbar IMM & 16 decodes to sleep.  */
1279badcbf9dSEdgar E. Iglesias         if (mbar_imm & 16) {
128041ba37c4SRichard Henderson             TCGv_i32 tmp_1;
1281fcf5ef2aSThomas Huth 
1282b4919e7dSEdgar E. Iglesias             if (trap_userspace(dc, true)) {
1283b4919e7dSEdgar E. Iglesias                 /* Sleep is a privileged instruction.  */
1284b4919e7dSEdgar E. Iglesias                 return;
1285b4919e7dSEdgar E. Iglesias             }
1286b4919e7dSEdgar E. Iglesias 
1287fcf5ef2aSThomas Huth             t_sync_flags(dc);
128841ba37c4SRichard Henderson 
128941ba37c4SRichard Henderson             tmp_1 = tcg_const_i32(1);
1290fcf5ef2aSThomas Huth             tcg_gen_st_i32(tmp_1, cpu_env,
1291fcf5ef2aSThomas Huth                            -offsetof(MicroBlazeCPU, env)
1292fcf5ef2aSThomas Huth                            +offsetof(CPUState, halted));
1293fcf5ef2aSThomas Huth             tcg_temp_free_i32(tmp_1);
129441ba37c4SRichard Henderson 
1295d4705ae0SRichard Henderson             tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
129641ba37c4SRichard Henderson 
129741ba37c4SRichard Henderson             gen_raise_exception(dc, EXCP_HLT);
1298fcf5ef2aSThomas Huth             return;
1299fcf5ef2aSThomas Huth         }
1300fcf5ef2aSThomas Huth         /* Break the TB.  */
1301fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1302fcf5ef2aSThomas Huth         return;
1303fcf5ef2aSThomas Huth     }
1304fcf5ef2aSThomas Huth 
1305d7ecb757SRichard Henderson     if (abs && link && !dslot) {
1306d7ecb757SRichard Henderson         if (dc->type_b) {
1307d7ecb757SRichard Henderson             /* BRKI */
1308d7ecb757SRichard Henderson             uint32_t imm = dec_alu_typeb_imm(dc);
1309d7ecb757SRichard Henderson             if (trap_userspace(dc, imm != 8 && imm != 0x18)) {
1310d7ecb757SRichard Henderson                 return;
1311d7ecb757SRichard Henderson             }
1312d7ecb757SRichard Henderson         } else {
1313d7ecb757SRichard Henderson             /* BRK */
1314d7ecb757SRichard Henderson             if (trap_userspace(dc, true)) {
1315d7ecb757SRichard Henderson                 return;
1316d7ecb757SRichard Henderson             }
1317d7ecb757SRichard Henderson         }
1318d7ecb757SRichard Henderson     }
1319d7ecb757SRichard Henderson 
1320fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1321fcf5ef2aSThomas Huth     if (dslot) {
1322f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1323fcf5ef2aSThomas Huth     }
1324d7ecb757SRichard Henderson     if (link && dc->rd) {
1325d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1326d7ecb757SRichard Henderson     }
1327fcf5ef2aSThomas Huth 
1328fcf5ef2aSThomas Huth     if (abs) {
1329d7ecb757SRichard Henderson         if (dc->type_b) {
1330d7ecb757SRichard Henderson             uint32_t dest = dec_alu_typeb_imm(dc);
1331d7ecb757SRichard Henderson 
1332d7ecb757SRichard Henderson             dc->jmp = JMP_DIRECT;
1333d7ecb757SRichard Henderson             dc->jmp_pc = dest;
1334d7ecb757SRichard Henderson             tcg_gen_movi_i32(cpu_btarget, dest);
1335fcf5ef2aSThomas Huth             if (link && !dslot) {
1336d7ecb757SRichard Henderson                 switch (dest) {
1337d7ecb757SRichard Henderson                 case 8:
1338d7ecb757SRichard Henderson                 case 0x18:
1339d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_BREAK);
1340d7ecb757SRichard Henderson                     break;
1341d7ecb757SRichard Henderson                 case 0:
1342d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_DEBUG);
1343d7ecb757SRichard Henderson                     break;
1344d7ecb757SRichard Henderson                 }
1345d7ecb757SRichard Henderson             }
1346d7ecb757SRichard Henderson         } else {
1347d7ecb757SRichard Henderson             dc->jmp = JMP_INDIRECT;
1348d7ecb757SRichard Henderson             tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]);
1349d7ecb757SRichard Henderson             if (link && !dslot) {
135041ba37c4SRichard Henderson                 gen_raise_exception_sync(dc, EXCP_BREAK);
135141ba37c4SRichard Henderson             }
1352fcf5ef2aSThomas Huth         }
1353d7ecb757SRichard Henderson     } else if (dc->type_b) {
1354fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT;
1355d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1356d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1357fcf5ef2aSThomas Huth     } else {
1358d7ecb757SRichard Henderson         dc->jmp = JMP_INDIRECT;
1359d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1360d7ecb757SRichard Henderson     }
13619b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
1362fcf5ef2aSThomas Huth }
1363fcf5ef2aSThomas Huth 
1364fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc)
1365fcf5ef2aSThomas Huth {
1366cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1367cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1368cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
13693e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
13700a22f8cfSEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
13710a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_IE);
1372cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1373fcf5ef2aSThomas Huth 
1374cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1375cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1376fcf5ef2aSThomas Huth     msr_write(dc, t1);
1377cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1378cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1379fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1380fcf5ef2aSThomas Huth }
1381fcf5ef2aSThomas Huth 
1382fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc)
1383fcf5ef2aSThomas Huth {
1384cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1385cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1386cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
13873e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
13880a22f8cfSEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
1389cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1390cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1391fcf5ef2aSThomas Huth 
1392cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1393cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1394fcf5ef2aSThomas Huth     msr_write(dc, t1);
1395cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1396cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1397fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1398fcf5ef2aSThomas Huth }
1399fcf5ef2aSThomas Huth 
1400fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc)
1401fcf5ef2aSThomas Huth {
1402cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1403cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1404cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
1405fcf5ef2aSThomas Huth 
14063e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
14070a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_EE);
1408cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
1409cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1410cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1411fcf5ef2aSThomas Huth 
1412cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1413cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1414fcf5ef2aSThomas Huth     msr_write(dc, t1);
1415cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1416cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1417fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1418fcf5ef2aSThomas Huth }
1419fcf5ef2aSThomas Huth 
1420fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc)
1421fcf5ef2aSThomas Huth {
1422fcf5ef2aSThomas Huth     unsigned int b_bit, i_bit, e_bit;
1423fcf5ef2aSThomas Huth 
1424fcf5ef2aSThomas Huth     i_bit = dc->ir & (1 << 21);
1425fcf5ef2aSThomas Huth     b_bit = dc->ir & (1 << 22);
1426fcf5ef2aSThomas Huth     e_bit = dc->ir & (1 << 23);
1427fcf5ef2aSThomas Huth 
1428bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
1429bdfc1e88SEdgar E. Iglesias         return;
1430bdfc1e88SEdgar E. Iglesias     }
1431bdfc1e88SEdgar E. Iglesias 
1432f91c60f0SEdgar E. Iglesias     dec_setup_dslot(dc);
1433fcf5ef2aSThomas Huth 
1434fcf5ef2aSThomas Huth     if (i_bit) {
1435fcf5ef2aSThomas Huth         dc->tb_flags |= DRTI_FLAG;
1436fcf5ef2aSThomas Huth     } else if (b_bit) {
1437fcf5ef2aSThomas Huth         dc->tb_flags |= DRTB_FLAG;
1438fcf5ef2aSThomas Huth     } else if (e_bit) {
1439fcf5ef2aSThomas Huth         dc->tb_flags |= DRTE_FLAG;
144011105d67SRichard Henderson     }
1441fcf5ef2aSThomas Huth 
1442fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
14439b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
14440f96e96bSRichard Henderson     tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc));
1445fcf5ef2aSThomas Huth }
1446fcf5ef2aSThomas Huth 
1447fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc)
1448fcf5ef2aSThomas Huth {
14499ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, true)) {
1450fcf5ef2aSThomas Huth         return;
1451fcf5ef2aSThomas Huth     }
1452d4705ae0SRichard Henderson     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n",
1453d4705ae0SRichard Henderson                   (uint32_t)dc->base.pc_next, dc->opcode);
1454fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 1;
1455fcf5ef2aSThomas Huth }
1456fcf5ef2aSThomas Huth 
1457fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
1458fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc)
1459fcf5ef2aSThomas Huth {
1460fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1461fcf5ef2aSThomas Huth     int ctrl;
1462fcf5ef2aSThomas Huth 
1463bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
1464fcf5ef2aSThomas Huth         return;
1465fcf5ef2aSThomas Huth     }
1466fcf5ef2aSThomas Huth 
1467cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
1468fcf5ef2aSThomas Huth     if (dc->type_b) {
1469cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(t_id, dc->imm & 0xf);
1470fcf5ef2aSThomas Huth         ctrl = dc->imm >> 10;
1471fcf5ef2aSThomas Huth     } else {
1472cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
1473fcf5ef2aSThomas Huth         ctrl = dc->imm >> 5;
1474fcf5ef2aSThomas Huth     }
1475fcf5ef2aSThomas Huth 
1476cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
1477fcf5ef2aSThomas Huth 
1478fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1479fcf5ef2aSThomas Huth         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1480fcf5ef2aSThomas Huth     } else {
1481fcf5ef2aSThomas Huth         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1482fcf5ef2aSThomas Huth     }
1483cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1484cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
1485fcf5ef2aSThomas Huth }
1486fcf5ef2aSThomas Huth 
1487fcf5ef2aSThomas Huth static struct decoder_info {
1488fcf5ef2aSThomas Huth     struct {
1489fcf5ef2aSThomas Huth         uint32_t bits;
1490fcf5ef2aSThomas Huth         uint32_t mask;
1491fcf5ef2aSThomas Huth     };
1492fcf5ef2aSThomas Huth     void (*dec)(DisasContext *dc);
1493fcf5ef2aSThomas Huth } decinfo[] = {
1494fcf5ef2aSThomas Huth     {DEC_LD, dec_load},
1495fcf5ef2aSThomas Huth     {DEC_ST, dec_store},
1496fcf5ef2aSThomas Huth     {DEC_BR, dec_br},
1497fcf5ef2aSThomas Huth     {DEC_BCC, dec_bcc},
1498fcf5ef2aSThomas Huth     {DEC_RTS, dec_rts},
1499fcf5ef2aSThomas Huth     {DEC_MSR, dec_msr},
1500fcf5ef2aSThomas Huth     {DEC_STREAM, dec_stream},
1501fcf5ef2aSThomas Huth     {{0, 0}, dec_null}
1502fcf5ef2aSThomas Huth };
1503fcf5ef2aSThomas Huth 
150444d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir)
1505fcf5ef2aSThomas Huth {
1506fcf5ef2aSThomas Huth     int i;
1507fcf5ef2aSThomas Huth 
1508fcf5ef2aSThomas Huth     dc->ir = ir;
1509fcf5ef2aSThomas Huth 
1510fcf5ef2aSThomas Huth     /* bit 2 seems to indicate insn type.  */
1511fcf5ef2aSThomas Huth     dc->type_b = ir & (1 << 29);
1512fcf5ef2aSThomas Huth 
1513fcf5ef2aSThomas Huth     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1514fcf5ef2aSThomas Huth     dc->rd = EXTRACT_FIELD(ir, 21, 25);
1515fcf5ef2aSThomas Huth     dc->ra = EXTRACT_FIELD(ir, 16, 20);
1516fcf5ef2aSThomas Huth     dc->rb = EXTRACT_FIELD(ir, 11, 15);
1517fcf5ef2aSThomas Huth     dc->imm = EXTRACT_FIELD(ir, 0, 15);
1518fcf5ef2aSThomas Huth 
1519fcf5ef2aSThomas Huth     /* Large switch for all insns.  */
1520fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1521fcf5ef2aSThomas Huth         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1522fcf5ef2aSThomas Huth             decinfo[i].dec(dc);
1523fcf5ef2aSThomas Huth             break;
1524fcf5ef2aSThomas Huth         }
1525fcf5ef2aSThomas Huth     }
1526fcf5ef2aSThomas Huth }
1527fcf5ef2aSThomas Huth 
1528372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1529fcf5ef2aSThomas Huth {
1530372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1531372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1532372122e3SRichard Henderson     int bound;
1533fcf5ef2aSThomas Huth 
1534fcf5ef2aSThomas Huth     dc->cpu = cpu;
1535372122e3SRichard Henderson     dc->synced_flags = dc->tb_flags = dc->base.tb->flags;
1536fcf5ef2aSThomas Huth     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
1537372122e3SRichard Henderson     dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP;
1538fcf5ef2aSThomas Huth     dc->cpustate_changed = 0;
1539fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 0;
1540d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
154120800179SRichard Henderson     dc->r0 = NULL;
154220800179SRichard Henderson     dc->r0_set = false;
1543fcf5ef2aSThomas Huth 
1544372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1545372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1546fcf5ef2aSThomas Huth }
1547fcf5ef2aSThomas Huth 
1548372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1549fcf5ef2aSThomas Huth {
1550fcf5ef2aSThomas Huth }
1551fcf5ef2aSThomas Huth 
1552372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1553372122e3SRichard Henderson {
1554372122e3SRichard Henderson     tcg_gen_insn_start(dcb->pc_next);
1555372122e3SRichard Henderson }
1556fcf5ef2aSThomas Huth 
1557372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1558372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1559372122e3SRichard Henderson {
1560372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1561372122e3SRichard Henderson 
1562372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1563372122e3SRichard Henderson 
1564372122e3SRichard Henderson     /*
1565372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1566372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1567372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1568372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1569372122e3SRichard Henderson      */
1570372122e3SRichard Henderson     dc->base.pc_next += 4;
1571372122e3SRichard Henderson     return true;
1572372122e3SRichard Henderson }
1573372122e3SRichard Henderson 
1574372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1575372122e3SRichard Henderson {
1576372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1577372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
157844d1432bSRichard Henderson     uint32_t ir;
1579372122e3SRichard Henderson 
1580372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1581372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1582372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1583372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1584fcf5ef2aSThomas Huth     }
1585fcf5ef2aSThomas Huth 
1586fcf5ef2aSThomas Huth     dc->clear_imm = 1;
158744d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
158844d1432bSRichard Henderson     if (!decode(dc, ir)) {
158944d1432bSRichard Henderson         old_decode(dc, ir);
159044d1432bSRichard Henderson     }
159120800179SRichard Henderson 
159220800179SRichard Henderson     if (dc->r0) {
159320800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
159420800179SRichard Henderson         dc->r0 = NULL;
159520800179SRichard Henderson         dc->r0_set = false;
159620800179SRichard Henderson     }
159720800179SRichard Henderson 
1598d7ecb757SRichard Henderson     if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) {
1599fcf5ef2aSThomas Huth         dc->tb_flags &= ~IMM_FLAG;
1600d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1601372122e3SRichard Henderson     }
1602d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1603fcf5ef2aSThomas Huth 
1604372122e3SRichard Henderson     if (dc->delayed_branch && --dc->delayed_branch == 0) {
1605372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
1606fcf5ef2aSThomas Huth             do_rti(dc);
1607372122e3SRichard Henderson         }
1608372122e3SRichard Henderson         if (dc->tb_flags & DRTB_FLAG) {
1609fcf5ef2aSThomas Huth             do_rtb(dc);
1610372122e3SRichard Henderson         }
1611372122e3SRichard Henderson         if (dc->tb_flags & DRTE_FLAG) {
1612fcf5ef2aSThomas Huth             do_rte(dc);
1613372122e3SRichard Henderson         }
1614fcf5ef2aSThomas Huth         /* Clear the delay slot flag.  */
1615fcf5ef2aSThomas Huth         dc->tb_flags &= ~D_FLAG;
1616372122e3SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1617372122e3SRichard Henderson     }
1618372122e3SRichard Henderson 
1619372122e3SRichard Henderson     /* Force an exit if the per-tb cpu state has changed.  */
1620372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
1621372122e3SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1622372122e3SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1623372122e3SRichard Henderson     }
1624372122e3SRichard Henderson }
1625372122e3SRichard Henderson 
1626372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1627372122e3SRichard Henderson {
1628372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1629372122e3SRichard Henderson 
1630372122e3SRichard Henderson     assert(!dc->abort_at_next_insn);
1631372122e3SRichard Henderson 
1632372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1633372122e3SRichard Henderson         /* We have already exited the TB. */
1634372122e3SRichard Henderson         return;
1635372122e3SRichard Henderson     }
1636372122e3SRichard Henderson 
1637372122e3SRichard Henderson     t_sync_flags(dc);
1638372122e3SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1639372122e3SRichard Henderson         sync_jmpstate(dc);
1640372122e3SRichard Henderson         dc->jmp = JMP_NOJMP;
1641372122e3SRichard Henderson     }
1642372122e3SRichard Henderson 
1643372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1644372122e3SRichard Henderson     case DISAS_TOO_MANY:
1645372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1646372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1647372122e3SRichard Henderson         return;
1648372122e3SRichard Henderson 
1649372122e3SRichard Henderson     case DISAS_UPDATE:
1650372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1651372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1652372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1653372122e3SRichard Henderson         } else {
1654372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1655372122e3SRichard Henderson         }
1656372122e3SRichard Henderson         return;
1657372122e3SRichard Henderson 
1658372122e3SRichard Henderson     case DISAS_JUMP:
1659372122e3SRichard Henderson         switch (dc->jmp) {
1660372122e3SRichard Henderson         case JMP_INDIRECT:
1661372122e3SRichard Henderson             {
1662d4705ae0SRichard Henderson                 TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next);
16630f96e96bSRichard Henderson                 eval_cond_jmp(dc, cpu_btarget, tmp_pc);
16640f96e96bSRichard Henderson                 tcg_temp_free_i32(tmp_pc);
1665372122e3SRichard Henderson 
1666372122e3SRichard Henderson                 if (unlikely(cs->singlestep_enabled)) {
1667372122e3SRichard Henderson                     gen_raise_exception(dc, EXCP_DEBUG);
1668372122e3SRichard Henderson                 } else {
1669372122e3SRichard Henderson                     tcg_gen_exit_tb(NULL, 0);
1670372122e3SRichard Henderson                 }
1671372122e3SRichard Henderson             }
1672372122e3SRichard Henderson             return;
1673372122e3SRichard Henderson 
1674372122e3SRichard Henderson         case JMP_DIRECT_CC:
1675372122e3SRichard Henderson             {
1676fcf5ef2aSThomas Huth                 TCGLabel *l1 = gen_new_label();
16779b158558SRichard Henderson                 tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1);
1678d4705ae0SRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1679fcf5ef2aSThomas Huth                 gen_set_label(l1);
1680372122e3SRichard Henderson             }
1681372122e3SRichard Henderson             /* fall through */
1682372122e3SRichard Henderson 
1683372122e3SRichard Henderson         case JMP_DIRECT:
1684fcf5ef2aSThomas Huth             gen_goto_tb(dc, 0, dc->jmp_pc);
1685372122e3SRichard Henderson             return;
1686fcf5ef2aSThomas Huth         }
1687372122e3SRichard Henderson         /* fall through */
1688fcf5ef2aSThomas Huth 
1689a2b80dbdSRichard Henderson     default:
1690a2b80dbdSRichard Henderson         g_assert_not_reached();
1691fcf5ef2aSThomas Huth     }
1692fcf5ef2aSThomas Huth }
1693fcf5ef2aSThomas Huth 
1694372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1695372122e3SRichard Henderson {
1696372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1697372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1698fcf5ef2aSThomas Huth }
1699372122e3SRichard Henderson 
1700372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1701372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1702372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1703372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1704372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1705372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1706372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1707372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1708372122e3SRichard Henderson };
1709372122e3SRichard Henderson 
1710372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1711372122e3SRichard Henderson {
1712372122e3SRichard Henderson     DisasContext dc;
1713372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1714fcf5ef2aSThomas Huth }
1715fcf5ef2aSThomas Huth 
171690c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1717fcf5ef2aSThomas Huth {
1718fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1719fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
1720fcf5ef2aSThomas Huth     int i;
1721fcf5ef2aSThomas Huth 
172290c84c56SMarkus Armbruster     if (!env) {
1723fcf5ef2aSThomas Huth         return;
172490c84c56SMarkus Armbruster     }
1725fcf5ef2aSThomas Huth 
17260f96e96bSRichard Henderson     qemu_fprintf(f, "IN: PC=%x %s\n",
172776e8187dSRichard Henderson                  env->pc, lookup_symbol(env->pc));
17286efd5599SRichard Henderson     qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " "
1729eb2022b7SRichard Henderson                  "imm=%x iflags=%x fsr=%x rbtr=%x\n",
173078e9caf2SRichard Henderson                  env->msr, env->esr, env->ear,
1731eb2022b7SRichard Henderson                  env->imm, env->iflags, env->fsr, env->btr);
17320f96e96bSRichard Henderson     qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
1733fcf5ef2aSThomas Huth                  env->btaken, env->btarget,
17342e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
17352e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
17362e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
17372e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
17382ead1b18SJoe Komlodi     for (i = 0; i < 12; i++) {
17392ead1b18SJoe Komlodi         qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]);
17402ead1b18SJoe Komlodi         if ((i + 1) % 4 == 0) {
17412ead1b18SJoe Komlodi             qemu_fprintf(f, "\n");
17422ead1b18SJoe Komlodi         }
17432ead1b18SJoe Komlodi     }
1744fcf5ef2aSThomas Huth 
17452ead1b18SJoe Komlodi     /* Registers that aren't modeled are reported as 0 */
174639db007eSRichard Henderson     qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 "
1747af20a93aSRichard Henderson                     "rtlblo=0 rtlbhi=0\n", env->edr);
17482ead1b18SJoe Komlodi     qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr);
1749fcf5ef2aSThomas Huth     for (i = 0; i < 32; i++) {
175090c84c56SMarkus Armbruster         qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1751fcf5ef2aSThomas Huth         if ((i + 1) % 4 == 0)
175290c84c56SMarkus Armbruster             qemu_fprintf(f, "\n");
1753fcf5ef2aSThomas Huth         }
175490c84c56SMarkus Armbruster     qemu_fprintf(f, "\n\n");
1755fcf5ef2aSThomas Huth }
1756fcf5ef2aSThomas Huth 
1757fcf5ef2aSThomas Huth void mb_tcg_init(void)
1758fcf5ef2aSThomas Huth {
1759480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1760480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1761fcf5ef2aSThomas Huth 
1762480d29a8SRichard Henderson     static const struct {
1763480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1764480d29a8SRichard Henderson     } i32s[] = {
1765480d29a8SRichard Henderson         R(0),  R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1766480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1767480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1768480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1769480d29a8SRichard Henderson 
1770480d29a8SRichard Henderson         SP(pc),
1771480d29a8SRichard Henderson         SP(msr),
17721074c0fbSRichard Henderson         SP(msr_c),
1773480d29a8SRichard Henderson         SP(imm),
1774480d29a8SRichard Henderson         SP(iflags),
1775480d29a8SRichard Henderson         SP(btaken),
1776480d29a8SRichard Henderson         SP(btarget),
1777480d29a8SRichard Henderson         SP(res_val),
1778480d29a8SRichard Henderson     };
1779480d29a8SRichard Henderson 
1780480d29a8SRichard Henderson #undef R
1781480d29a8SRichard Henderson #undef SP
1782480d29a8SRichard Henderson 
1783480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1784480d29a8SRichard Henderson         *i32s[i].var =
1785480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1786fcf5ef2aSThomas Huth     }
178776e8187dSRichard Henderson 
1788480d29a8SRichard Henderson     cpu_res_addr =
1789480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1790fcf5ef2aSThomas Huth }
1791fcf5ef2aSThomas Huth 
1792fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1793fcf5ef2aSThomas Huth                           target_ulong *data)
1794fcf5ef2aSThomas Huth {
179576e8187dSRichard Henderson     env->pc = data[0];
1796fcf5ef2aSThomas Huth }
1797