xref: /openbmc/qemu/target/microblaze/translate.c (revision 6f9642d7d799c4774e9e04f95679d370d52633c6)
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 
61683a247eSRichard Henderson     /* TCG op of the current insn_start.  */
62683a247eSRichard Henderson     TCGOp *insn_start;
63683a247eSRichard Henderson 
6420800179SRichard Henderson     TCGv_i32 r0;
6520800179SRichard Henderson     bool r0_set;
6620800179SRichard Henderson 
67fcf5ef2aSThomas Huth     /* Decoder.  */
68fcf5ef2aSThomas Huth     int type_b;
69fcf5ef2aSThomas Huth     uint32_t ir;
70d7ecb757SRichard Henderson     uint32_t ext_imm;
71fcf5ef2aSThomas Huth     uint8_t opcode;
72fcf5ef2aSThomas Huth     uint8_t rd, ra, rb;
73fcf5ef2aSThomas Huth     uint16_t imm;
74fcf5ef2aSThomas Huth 
75fcf5ef2aSThomas Huth     unsigned int cpustate_changed;
76fcf5ef2aSThomas Huth     unsigned int delayed_branch;
77683a247eSRichard Henderson     unsigned int tb_flags;
78*6f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
79287b1defSRichard Henderson     int mem_index;
80fcf5ef2aSThomas Huth 
81fcf5ef2aSThomas Huth #define JMP_NOJMP     0
82fcf5ef2aSThomas Huth #define JMP_DIRECT    1
83fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2
84fcf5ef2aSThomas Huth #define JMP_INDIRECT  3
85fcf5ef2aSThomas Huth     unsigned int jmp;
86fcf5ef2aSThomas Huth     uint32_t jmp_pc;
87fcf5ef2aSThomas Huth 
88fcf5ef2aSThomas Huth     int abort_at_next_insn;
89fcf5ef2aSThomas Huth } DisasContext;
90fcf5ef2aSThomas Huth 
9120800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
9220800179SRichard Henderson {
9320800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
9420800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
9520800179SRichard Henderson     }
9620800179SRichard Henderson     return x;
9720800179SRichard Henderson }
9820800179SRichard Henderson 
9944d1432bSRichard Henderson /* Include the auto-generated decoder.  */
10044d1432bSRichard Henderson #include "decode-insns.c.inc"
10144d1432bSRichard Henderson 
102683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
103fcf5ef2aSThomas Huth {
104fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
105683a247eSRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) {
106683a247eSRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK);
107fcf5ef2aSThomas Huth     }
108fcf5ef2aSThomas Huth }
109fcf5ef2aSThomas Huth 
110d8e59c4aSRichard Henderson static inline void sync_jmpstate(DisasContext *dc)
111d8e59c4aSRichard Henderson {
112d8e59c4aSRichard Henderson     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
113d8e59c4aSRichard Henderson         if (dc->jmp == JMP_DIRECT) {
114d8e59c4aSRichard Henderson             tcg_gen_movi_i32(cpu_btaken, 1);
115d8e59c4aSRichard Henderson         }
116d8e59c4aSRichard Henderson         dc->jmp = JMP_INDIRECT;
117d8e59c4aSRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
118d8e59c4aSRichard Henderson     }
119d8e59c4aSRichard Henderson }
120d8e59c4aSRichard Henderson 
12141ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
122fcf5ef2aSThomas Huth {
123fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
124fcf5ef2aSThomas Huth 
125fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
126fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
127d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
128fcf5ef2aSThomas Huth }
129fcf5ef2aSThomas Huth 
13041ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
13141ba37c4SRichard Henderson {
13241ba37c4SRichard Henderson     t_sync_flags(dc);
133d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
13441ba37c4SRichard Henderson     gen_raise_exception(dc, index);
13541ba37c4SRichard Henderson }
13641ba37c4SRichard Henderson 
13741ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
13841ba37c4SRichard Henderson {
13941ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
14041ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
14141ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
14241ba37c4SRichard Henderson 
14341ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
14441ba37c4SRichard Henderson }
14541ba37c4SRichard Henderson 
146fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
147fcf5ef2aSThomas Huth {
148fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
149d4705ae0SRichard Henderson     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
150fcf5ef2aSThomas Huth #else
151fcf5ef2aSThomas Huth     return true;
152fcf5ef2aSThomas Huth #endif
153fcf5ef2aSThomas Huth }
154fcf5ef2aSThomas Huth 
155fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
156fcf5ef2aSThomas Huth {
157d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1580b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1590b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1600b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1610b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
1620b46fa08SRichard Henderson     } else if (use_goto_tb(dc, dest)) {
163fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1640f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
165d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
166fcf5ef2aSThomas Huth     } else {
1670f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
16807ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
169fcf5ef2aSThomas Huth     }
170d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
171fcf5ef2aSThomas Huth }
172fcf5ef2aSThomas Huth 
173bdfc1e88SEdgar E. Iglesias /*
1749ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1759ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1769ba8cd45SEdgar E. Iglesias  */
1779ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1789ba8cd45SEdgar E. Iglesias {
1792c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1805143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
18141ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1829ba8cd45SEdgar E. Iglesias     }
1839ba8cd45SEdgar E. Iglesias     return cond;
1849ba8cd45SEdgar E. Iglesias }
1859ba8cd45SEdgar E. Iglesias 
1869ba8cd45SEdgar E. Iglesias /*
187bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
188bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
189bdfc1e88SEdgar E. Iglesias  */
190bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
191bdfc1e88SEdgar E. Iglesias {
192287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
193bdfc1e88SEdgar E. Iglesias 
1942c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
19541ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
196bdfc1e88SEdgar E. Iglesias     }
197bdfc1e88SEdgar E. Iglesias     return cond_user;
198bdfc1e88SEdgar E. Iglesias }
199bdfc1e88SEdgar E. Iglesias 
200d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc)
201fcf5ef2aSThomas Huth {
202d7ecb757SRichard Henderson     tcg_debug_assert(dc->type_b);
20320800179SRichard Henderson     return typeb_imm(dc, (int16_t)dc->imm);
204fcf5ef2aSThomas Huth }
205fcf5ef2aSThomas Huth 
206cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
207fcf5ef2aSThomas Huth {
208fcf5ef2aSThomas Huth     if (dc->type_b) {
209d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc));
2109b158558SRichard Henderson         return &cpu_imm;
211d7ecb757SRichard Henderson     }
212fcf5ef2aSThomas Huth     return &cpu_R[dc->rb];
213fcf5ef2aSThomas Huth }
214fcf5ef2aSThomas Huth 
21520800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
216fcf5ef2aSThomas Huth {
21720800179SRichard Henderson     if (likely(reg != 0)) {
21820800179SRichard Henderson         return cpu_R[reg];
219fcf5ef2aSThomas Huth     }
22020800179SRichard Henderson     if (!dc->r0_set) {
22120800179SRichard Henderson         if (dc->r0 == NULL) {
22220800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
223fcf5ef2aSThomas Huth         }
22420800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
22520800179SRichard Henderson         dc->r0_set = true;
22620800179SRichard Henderson     }
22720800179SRichard Henderson     return dc->r0;
228fcf5ef2aSThomas Huth }
229fcf5ef2aSThomas Huth 
23020800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
23120800179SRichard Henderson {
23220800179SRichard Henderson     if (likely(reg != 0)) {
23320800179SRichard Henderson         return cpu_R[reg];
23420800179SRichard Henderson     }
23520800179SRichard Henderson     if (dc->r0 == NULL) {
23620800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
23720800179SRichard Henderson     }
23820800179SRichard Henderson     return dc->r0;
239fcf5ef2aSThomas Huth }
240fcf5ef2aSThomas Huth 
24120800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
24220800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
24320800179SRichard Henderson {
24420800179SRichard Henderson     TCGv_i32 rd, ra, rb;
24520800179SRichard Henderson 
24620800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24720800179SRichard Henderson         return true;
248fcf5ef2aSThomas Huth     }
24920800179SRichard Henderson 
25020800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
25120800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
25220800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
25320800179SRichard Henderson     fn(rd, ra, rb);
25420800179SRichard Henderson     return true;
25520800179SRichard Henderson }
25620800179SRichard Henderson 
25739cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
25839cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
25939cf3864SRichard Henderson {
26039cf3864SRichard Henderson     TCGv_i32 rd, ra;
26139cf3864SRichard Henderson 
26239cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
26339cf3864SRichard Henderson         return true;
26439cf3864SRichard Henderson     }
26539cf3864SRichard Henderson 
26639cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26739cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
26839cf3864SRichard Henderson     fn(rd, ra);
26939cf3864SRichard Henderson     return true;
27039cf3864SRichard Henderson }
27139cf3864SRichard Henderson 
27220800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
27320800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
27420800179SRichard Henderson {
27520800179SRichard Henderson     TCGv_i32 rd, ra;
27620800179SRichard Henderson 
27720800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
27820800179SRichard Henderson         return true;
27920800179SRichard Henderson     }
28020800179SRichard Henderson 
28120800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
28220800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
28320800179SRichard Henderson     fni(rd, ra, arg->imm);
28420800179SRichard Henderson     return true;
28520800179SRichard Henderson }
28620800179SRichard Henderson 
28720800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
28820800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
28920800179SRichard Henderson {
29020800179SRichard Henderson     TCGv_i32 rd, ra, imm;
29120800179SRichard Henderson 
29220800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
29320800179SRichard Henderson         return true;
29420800179SRichard Henderson     }
29520800179SRichard Henderson 
29620800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
29720800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
29820800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
29920800179SRichard Henderson 
30020800179SRichard Henderson     fn(rd, ra, imm);
30120800179SRichard Henderson 
30220800179SRichard Henderson     tcg_temp_free_i32(imm);
30320800179SRichard Henderson     return true;
30420800179SRichard Henderson }
30520800179SRichard Henderson 
30620800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
30720800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
30820800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
30920800179SRichard Henderson 
310607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
311607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
312607f5767SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); }
313607f5767SRichard Henderson 
31439cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
31539cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
31639cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
31739cf3864SRichard Henderson 
31839cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
31939cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
32039cf3864SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); }
32139cf3864SRichard Henderson 
32220800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
32320800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
32420800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
32520800179SRichard Henderson 
32697955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
32797955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
32897955cebSRichard Henderson     { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); }
32997955cebSRichard Henderson 
33020800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
33120800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
33220800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
33320800179SRichard Henderson 
334d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
335d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
336d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
337d5aead3dSRichard Henderson 
338d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
339d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
340d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
341d5aead3dSRichard Henderson 
34220800179SRichard Henderson /* No input carry, but output carry. */
34320800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
34420800179SRichard Henderson {
34520800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
34620800179SRichard Henderson 
34720800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
34820800179SRichard Henderson 
34920800179SRichard Henderson     tcg_temp_free_i32(zero);
35020800179SRichard Henderson }
35120800179SRichard Henderson 
35220800179SRichard Henderson /* Input and output carry. */
35320800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
35420800179SRichard Henderson {
35520800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
35620800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
35720800179SRichard Henderson 
35820800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
35920800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
36020800179SRichard Henderson 
36120800179SRichard Henderson     tcg_temp_free_i32(tmp);
36220800179SRichard Henderson     tcg_temp_free_i32(zero);
36320800179SRichard Henderson }
36420800179SRichard Henderson 
36520800179SRichard Henderson /* Input carry, but no output carry. */
36620800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
36720800179SRichard Henderson {
36820800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
36920800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
37020800179SRichard Henderson }
37120800179SRichard Henderson 
37220800179SRichard Henderson DO_TYPEA(add, true, gen_add)
37320800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
37420800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
37520800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
37620800179SRichard Henderson 
37720800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
37820800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
37920800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
38020800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
38120800179SRichard Henderson 
382cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
383cb0a0a4cSRichard Henderson {
384cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
385cb0a0a4cSRichard Henderson }
386cb0a0a4cSRichard Henderson 
387cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
388cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
389cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
390cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
391cb0a0a4cSRichard Henderson 
392081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
393081d8e02SRichard Henderson {
394081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
395081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
396081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
397081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
398081d8e02SRichard Henderson }
399081d8e02SRichard Henderson 
400081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
401081d8e02SRichard Henderson {
402081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
403081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
404081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
405081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
406081d8e02SRichard Henderson }
407081d8e02SRichard Henderson 
408081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
409081d8e02SRichard Henderson {
410081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
411081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
412081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
413081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
414081d8e02SRichard Henderson }
415081d8e02SRichard Henderson 
416081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
417081d8e02SRichard Henderson {
418081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
419081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
420081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
421081d8e02SRichard Henderson 
422081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
423081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
424081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
425081d8e02SRichard Henderson                       imm_w, imm_s);
426081d8e02SRichard Henderson     } else {
427081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
428081d8e02SRichard Henderson     }
429081d8e02SRichard Henderson }
430081d8e02SRichard Henderson 
431081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
432081d8e02SRichard Henderson {
433081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
434081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
435081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
436081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
437081d8e02SRichard Henderson 
438081d8e02SRichard Henderson     if (imm_w < imm_s) {
439081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
440081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
441081d8e02SRichard Henderson                       imm_w, imm_s);
442081d8e02SRichard Henderson     } else {
443081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
444081d8e02SRichard Henderson     }
445081d8e02SRichard Henderson }
446081d8e02SRichard Henderson 
447081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
448081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
449081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
450081d8e02SRichard Henderson 
451081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
452081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
453081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
454081d8e02SRichard Henderson 
455081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
456081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
457081d8e02SRichard Henderson 
45839cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
45939cf3864SRichard Henderson {
46039cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
46139cf3864SRichard Henderson }
46239cf3864SRichard Henderson 
46339cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
46439cf3864SRichard Henderson 
46558b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
46658b48b63SRichard Henderson {
46758b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
46858b48b63SRichard Henderson 
46958b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
47058b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
47158b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
47258b48b63SRichard Henderson     tcg_temp_free_i32(lt);
47358b48b63SRichard Henderson }
47458b48b63SRichard Henderson 
47558b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
47658b48b63SRichard Henderson {
47758b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
47858b48b63SRichard Henderson 
47958b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
48058b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
48158b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
48258b48b63SRichard Henderson     tcg_temp_free_i32(lt);
48358b48b63SRichard Henderson }
48458b48b63SRichard Henderson 
48558b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
48658b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
487a2b0b90eSRichard Henderson 
488d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
489d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
490d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
491d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
492d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
493d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
494d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
495d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
496d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
497d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
498d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
499d5aead3dSRichard Henderson 
500d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
501d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
502d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
503d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
504d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
505d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
506d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
507d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
508d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
509d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
510d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
511d5aead3dSRichard Henderson 
512d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
513d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
514d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
515d5aead3dSRichard Henderson 
516d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
517d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
518d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
519d5aead3dSRichard Henderson 
520d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
521b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
522b1354342SRichard Henderson {
523b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
524b1354342SRichard Henderson }
525b1354342SRichard Henderson 
526b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
527b1354342SRichard Henderson {
528b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
529b1354342SRichard Henderson }
530b1354342SRichard Henderson 
531b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
532b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
533b1354342SRichard Henderson 
534e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
535e64b2e5cSRichard Henderson {
536e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
537e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
538*6f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
539e64b2e5cSRichard Henderson     return true;
540e64b2e5cSRichard Henderson }
541e64b2e5cSRichard Henderson 
54297955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
54397955cebSRichard Henderson {
54497955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
54597955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
54697955cebSRichard Henderson     tcg_temp_free_i32(tmp);
54797955cebSRichard Henderson }
54897955cebSRichard Henderson 
54997955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
55097955cebSRichard Henderson {
55197955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
55297955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
55397955cebSRichard Henderson     tcg_temp_free_i32(tmp);
55497955cebSRichard Henderson }
55597955cebSRichard Henderson 
55697955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
55797955cebSRichard Henderson {
55897955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
55997955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
56097955cebSRichard Henderson     tcg_temp_free_i32(tmp);
56197955cebSRichard Henderson }
56297955cebSRichard Henderson 
56397955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
56497955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
56597955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
56697955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
56797955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
56897955cebSRichard Henderson 
569cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
570cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
571cb0a0a4cSRichard Henderson 
572607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
573607f5767SRichard Henderson {
574607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
575607f5767SRichard Henderson }
576607f5767SRichard Henderson 
577607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
578607f5767SRichard Henderson {
579607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
580607f5767SRichard Henderson }
581607f5767SRichard Henderson 
582607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
583607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
584607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
585607f5767SRichard Henderson 
586a2b0b90eSRichard Henderson /* No input carry, but output carry. */
587a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
588a2b0b90eSRichard Henderson {
589a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
590a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
591a2b0b90eSRichard Henderson }
592a2b0b90eSRichard Henderson 
593a2b0b90eSRichard Henderson /* Input and output carry. */
594a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
595a2b0b90eSRichard Henderson {
596a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
597a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
598a2b0b90eSRichard Henderson 
599a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
600a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
601a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
602a2b0b90eSRichard Henderson 
603a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
604a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
605a2b0b90eSRichard Henderson }
606a2b0b90eSRichard Henderson 
607a2b0b90eSRichard Henderson /* No input or output carry. */
608a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
609a2b0b90eSRichard Henderson {
610a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
611a2b0b90eSRichard Henderson }
612a2b0b90eSRichard Henderson 
613a2b0b90eSRichard Henderson /* Input carry, no output carry. */
614a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
615a2b0b90eSRichard Henderson {
616a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
617a2b0b90eSRichard Henderson 
618a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
619a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
620a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
621a2b0b90eSRichard Henderson 
622a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
623a2b0b90eSRichard Henderson }
624a2b0b90eSRichard Henderson 
625a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
626a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
627a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
628a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
629a2b0b90eSRichard Henderson 
630a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
631a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
632a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
633a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
634a2b0b90eSRichard Henderson 
63539cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
63639cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
63739cf3864SRichard Henderson 
63839cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
63939cf3864SRichard Henderson {
64039cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
64139cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
64239cf3864SRichard Henderson }
64339cf3864SRichard Henderson 
64439cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
64539cf3864SRichard Henderson {
64639cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
64739cf3864SRichard Henderson 
64839cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
64939cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
65039cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
65139cf3864SRichard Henderson 
65239cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
65339cf3864SRichard Henderson }
65439cf3864SRichard Henderson 
65539cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
65639cf3864SRichard Henderson {
65739cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
65839cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
65939cf3864SRichard Henderson }
66039cf3864SRichard Henderson 
66139cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
66239cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
66339cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
66439cf3864SRichard Henderson 
66539cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
66639cf3864SRichard Henderson {
66739cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
66839cf3864SRichard Henderson }
66939cf3864SRichard Henderson 
67039cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
67139cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
67239cf3864SRichard Henderson 
67339cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
67439cf3864SRichard Henderson {
67539cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
67639cf3864SRichard Henderson     trap_userspace(dc, true);
67739cf3864SRichard Henderson     return true;
67839cf3864SRichard Henderson }
67939cf3864SRichard Henderson 
680cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
681cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
682cb0a0a4cSRichard Henderson 
683d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
684d8e59c4aSRichard Henderson {
685d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
686d8e59c4aSRichard Henderson 
687d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
688d8e59c4aSRichard Henderson     if (ra && rb) {
689d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
690d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
691d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
692d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
693d8e59c4aSRichard Henderson     } else if (ra) {
694d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
695d8e59c4aSRichard Henderson     } else if (rb) {
696d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
697d8e59c4aSRichard Henderson     } else {
698d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
699d8e59c4aSRichard Henderson     }
700d8e59c4aSRichard Henderson 
701d8e59c4aSRichard Henderson     if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) {
702d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
703d8e59c4aSRichard Henderson     }
704d8e59c4aSRichard Henderson     return ret;
705d8e59c4aSRichard Henderson }
706d8e59c4aSRichard Henderson 
707d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
708d8e59c4aSRichard Henderson {
709d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
710d8e59c4aSRichard Henderson 
711d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
712d8e59c4aSRichard Henderson     if (ra) {
713d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
714d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
715d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
716d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
717d8e59c4aSRichard Henderson     } else {
718d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
719d8e59c4aSRichard Henderson     }
720d8e59c4aSRichard Henderson 
721d8e59c4aSRichard Henderson     if (ra == 1 && dc->cpu->cfg.stackprot) {
722d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
723d8e59c4aSRichard Henderson     }
724d8e59c4aSRichard Henderson     return ret;
725d8e59c4aSRichard Henderson }
726d8e59c4aSRichard Henderson 
727d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
728d8e59c4aSRichard Henderson {
729d8e59c4aSRichard Henderson     int addr_size = dc->cpu->cfg.addr_size;
730d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
731d8e59c4aSRichard Henderson 
732d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
733d8e59c4aSRichard Henderson         if (rb) {
734d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
735d8e59c4aSRichard Henderson         } else {
736d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
737d8e59c4aSRichard Henderson         }
738d8e59c4aSRichard Henderson     } else {
739d8e59c4aSRichard Henderson         if (rb) {
740d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
741d8e59c4aSRichard Henderson         } else {
742d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
743d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
744d8e59c4aSRichard Henderson         }
745d8e59c4aSRichard Henderson         if (addr_size < 64) {
746d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
747d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
748d8e59c4aSRichard Henderson         }
749d8e59c4aSRichard Henderson     }
750d8e59c4aSRichard Henderson     return ret;
751d8e59c4aSRichard Henderson }
752d8e59c4aSRichard Henderson 
753ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
754ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
755ab0c8d0fSRichard Henderson {
756ab0c8d0fSRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
757ab0c8d0fSRichard Henderson 
758ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
759ab0c8d0fSRichard Henderson     iflags |= rd << 5;
760ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
761ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
762ab0c8d0fSRichard Henderson 
763ab0c8d0fSRichard Henderson     tcg_set_insn_start_param(dc->insn_start, 1, iflags);
764ab0c8d0fSRichard Henderson }
765ab0c8d0fSRichard Henderson 
766d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
767d8e59c4aSRichard Henderson                     int mem_index, bool rev)
768d8e59c4aSRichard Henderson {
769d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
770d8e59c4aSRichard Henderson 
771d8e59c4aSRichard Henderson     /*
772d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
773d8e59c4aSRichard Henderson      *
774d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
775d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
776d8e59c4aSRichard Henderson      */
777d8e59c4aSRichard Henderson     if (rev) {
778d8e59c4aSRichard Henderson         if (size > MO_8) {
779d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
780d8e59c4aSRichard Henderson         }
781d8e59c4aSRichard Henderson         if (size < MO_32) {
782d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
783d8e59c4aSRichard Henderson         }
784d8e59c4aSRichard Henderson     }
785d8e59c4aSRichard Henderson 
786d8e59c4aSRichard Henderson     sync_jmpstate(dc);
787d8e59c4aSRichard Henderson 
788ab0c8d0fSRichard Henderson     if (size > MO_8 &&
789ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
790ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
791ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
792ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
793d8e59c4aSRichard Henderson     }
794d8e59c4aSRichard Henderson 
795ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
796d8e59c4aSRichard Henderson 
797d8e59c4aSRichard Henderson     tcg_temp_free(addr);
798d8e59c4aSRichard Henderson     return true;
799d8e59c4aSRichard Henderson }
800d8e59c4aSRichard Henderson 
801d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
802d8e59c4aSRichard Henderson {
803d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
804d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
805d8e59c4aSRichard Henderson }
806d8e59c4aSRichard Henderson 
807d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
808d8e59c4aSRichard Henderson {
809d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
810d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
811d8e59c4aSRichard Henderson }
812d8e59c4aSRichard Henderson 
813d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
814d8e59c4aSRichard Henderson {
815d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
816d8e59c4aSRichard Henderson         return true;
817d8e59c4aSRichard Henderson     }
818d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
819d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
820d8e59c4aSRichard Henderson }
821d8e59c4aSRichard Henderson 
822d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
823d8e59c4aSRichard Henderson {
824d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
825d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
826d8e59c4aSRichard Henderson }
827d8e59c4aSRichard Henderson 
828d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
829d8e59c4aSRichard Henderson {
830d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
831d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
832d8e59c4aSRichard Henderson }
833d8e59c4aSRichard Henderson 
834d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
835d8e59c4aSRichard Henderson {
836d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
837d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
838d8e59c4aSRichard Henderson }
839d8e59c4aSRichard Henderson 
840d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
841d8e59c4aSRichard Henderson {
842d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
843d8e59c4aSRichard Henderson         return true;
844d8e59c4aSRichard Henderson     }
845d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
846d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
847d8e59c4aSRichard Henderson }
848d8e59c4aSRichard Henderson 
849d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
850d8e59c4aSRichard Henderson {
851d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
852d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
853d8e59c4aSRichard Henderson }
854d8e59c4aSRichard Henderson 
855d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
856d8e59c4aSRichard Henderson {
857d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
858d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
859d8e59c4aSRichard Henderson }
860d8e59c4aSRichard Henderson 
861d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
862d8e59c4aSRichard Henderson {
863d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
864d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
865d8e59c4aSRichard Henderson }
866d8e59c4aSRichard Henderson 
867d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
868d8e59c4aSRichard Henderson {
869d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
870d8e59c4aSRichard Henderson         return true;
871d8e59c4aSRichard Henderson     }
872d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
873d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
874d8e59c4aSRichard Henderson }
875d8e59c4aSRichard Henderson 
876d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
877d8e59c4aSRichard Henderson {
878d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
879d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
880d8e59c4aSRichard Henderson }
881d8e59c4aSRichard Henderson 
882d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
883d8e59c4aSRichard Henderson {
884d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
885d8e59c4aSRichard Henderson 
886d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
887d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
888d8e59c4aSRichard Henderson 
889d8e59c4aSRichard Henderson     sync_jmpstate(dc);
890d8e59c4aSRichard Henderson 
891d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
892d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
893d8e59c4aSRichard Henderson     tcg_temp_free(addr);
894d8e59c4aSRichard Henderson 
895d8e59c4aSRichard Henderson     if (arg->rd) {
896d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
897d8e59c4aSRichard Henderson     }
898d8e59c4aSRichard Henderson 
899d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
900d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
901d8e59c4aSRichard Henderson     return true;
902d8e59c4aSRichard Henderson }
903d8e59c4aSRichard Henderson 
904d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
905d8e59c4aSRichard Henderson                      int mem_index, bool rev)
906d8e59c4aSRichard Henderson {
907d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
908d8e59c4aSRichard Henderson 
909d8e59c4aSRichard Henderson     /*
910d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
911d8e59c4aSRichard Henderson      *
912d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
913d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
914d8e59c4aSRichard Henderson      */
915d8e59c4aSRichard Henderson     if (rev) {
916d8e59c4aSRichard Henderson         if (size > MO_8) {
917d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
918d8e59c4aSRichard Henderson         }
919d8e59c4aSRichard Henderson         if (size < MO_32) {
920d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
921d8e59c4aSRichard Henderson         }
922d8e59c4aSRichard Henderson     }
923d8e59c4aSRichard Henderson 
924d8e59c4aSRichard Henderson     sync_jmpstate(dc);
925d8e59c4aSRichard Henderson 
926ab0c8d0fSRichard Henderson     if (size > MO_8 &&
927ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
928ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
929ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
930ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
931d8e59c4aSRichard Henderson     }
932d8e59c4aSRichard Henderson 
933ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
934ab0c8d0fSRichard Henderson 
935d8e59c4aSRichard Henderson     tcg_temp_free(addr);
936d8e59c4aSRichard Henderson     return true;
937d8e59c4aSRichard Henderson }
938d8e59c4aSRichard Henderson 
939d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
940d8e59c4aSRichard Henderson {
941d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
942d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
943d8e59c4aSRichard Henderson }
944d8e59c4aSRichard Henderson 
945d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
946d8e59c4aSRichard Henderson {
947d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
948d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
949d8e59c4aSRichard Henderson }
950d8e59c4aSRichard Henderson 
951d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
952d8e59c4aSRichard Henderson {
953d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
954d8e59c4aSRichard Henderson         return true;
955d8e59c4aSRichard Henderson     }
956d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
957d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
958d8e59c4aSRichard Henderson }
959d8e59c4aSRichard Henderson 
960d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
961d8e59c4aSRichard Henderson {
962d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
963d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
964d8e59c4aSRichard Henderson }
965d8e59c4aSRichard Henderson 
966d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
967d8e59c4aSRichard Henderson {
968d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
969d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
970d8e59c4aSRichard Henderson }
971d8e59c4aSRichard Henderson 
972d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
973d8e59c4aSRichard Henderson {
974d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
975d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
976d8e59c4aSRichard Henderson }
977d8e59c4aSRichard Henderson 
978d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
979d8e59c4aSRichard Henderson {
980d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
981d8e59c4aSRichard Henderson         return true;
982d8e59c4aSRichard Henderson     }
983d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
984d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
985d8e59c4aSRichard Henderson }
986d8e59c4aSRichard Henderson 
987d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
988d8e59c4aSRichard Henderson {
989d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
990d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
991d8e59c4aSRichard Henderson }
992d8e59c4aSRichard Henderson 
993d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
994d8e59c4aSRichard Henderson {
995d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
996d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
997d8e59c4aSRichard Henderson }
998d8e59c4aSRichard Henderson 
999d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
1000d8e59c4aSRichard Henderson {
1001d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1002d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
1003d8e59c4aSRichard Henderson }
1004d8e59c4aSRichard Henderson 
1005d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
1006d8e59c4aSRichard Henderson {
1007d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
1008d8e59c4aSRichard Henderson         return true;
1009d8e59c4aSRichard Henderson     }
1010d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1011d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
1012d8e59c4aSRichard Henderson }
1013d8e59c4aSRichard Henderson 
1014d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1015d8e59c4aSRichard Henderson {
1016d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1017d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1018d8e59c4aSRichard Henderson }
1019d8e59c4aSRichard Henderson 
1020d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1021d8e59c4aSRichard Henderson {
1022d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1023d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1024d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1025d8e59c4aSRichard Henderson     TCGv_i32 tval;
1026d8e59c4aSRichard Henderson 
1027d8e59c4aSRichard Henderson     sync_jmpstate(dc);
1028d8e59c4aSRichard Henderson 
1029d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1030d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1031d8e59c4aSRichard Henderson 
1032d8e59c4aSRichard Henderson     /*
1033d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1034d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1035d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1036d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1037d8e59c4aSRichard Henderson      */
1038d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1039d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1040d8e59c4aSRichard Henderson 
1041d8e59c4aSRichard Henderson     /*
1042d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1043d8e59c4aSRichard Henderson      * the reserved location.
1044d8e59c4aSRichard Henderson      */
1045d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1046d8e59c4aSRichard Henderson 
1047d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1048d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1049d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1050d8e59c4aSRichard Henderson 
1051d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1052d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1053d8e59c4aSRichard Henderson 
1054d8e59c4aSRichard Henderson     /* Success */
1055d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1056d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1057d8e59c4aSRichard Henderson 
1058d8e59c4aSRichard Henderson     /* Failure */
1059d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1060d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1061d8e59c4aSRichard Henderson 
1062d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1063d8e59c4aSRichard Henderson 
1064d8e59c4aSRichard Henderson     /*
1065d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1066d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1067d8e59c4aSRichard Henderson      */
1068d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1069d8e59c4aSRichard Henderson     return true;
1070d8e59c4aSRichard Henderson }
1071d8e59c4aSRichard Henderson 
107220800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
107320800179SRichard Henderson {
107420800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
107520800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
107620800179SRichard Henderson         trap_illegal(dc, true);
107720800179SRichard Henderson         return true;
107820800179SRichard Henderson     }
107920800179SRichard Henderson     /*
108020800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
108120800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
108220800179SRichard Henderson      */
108320800179SRichard Henderson     return false;
1084fcf5ef2aSThomas Huth }
1085fcf5ef2aSThomas Huth 
10861074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1087fcf5ef2aSThomas Huth {
10881074c0fbSRichard Henderson     TCGv_i32 t;
10891074c0fbSRichard Henderson 
10901074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
10911074c0fbSRichard Henderson     t = tcg_temp_new_i32();
10921074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
10931074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
10941074c0fbSRichard Henderson     tcg_temp_free_i32(t);
1095fcf5ef2aSThomas Huth }
1096fcf5ef2aSThomas Huth 
10971074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v)
1098fcf5ef2aSThomas Huth {
1099fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
11001074c0fbSRichard Henderson 
11011074c0fbSRichard Henderson     /* Install MSR_C.  */
11021074c0fbSRichard Henderson     tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
11031074c0fbSRichard Henderson 
11041074c0fbSRichard Henderson     /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
11051074c0fbSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
1106fcf5ef2aSThomas Huth }
1107fcf5ef2aSThomas Huth 
1108fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc)
1109fcf5ef2aSThomas Huth {
1110fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
1111cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
11122023e9a3SEdgar E. Iglesias     unsigned int sr, rn;
1113f0f7e7f7SEdgar E. Iglesias     bool to, clrset, extended = false;
1114fcf5ef2aSThomas Huth 
11152023e9a3SEdgar E. Iglesias     sr = extract32(dc->imm, 0, 14);
11162023e9a3SEdgar E. Iglesias     to = extract32(dc->imm, 14, 1);
11172023e9a3SEdgar E. Iglesias     clrset = extract32(dc->imm, 15, 1) == 0;
1118fcf5ef2aSThomas Huth     dc->type_b = 1;
11192023e9a3SEdgar E. Iglesias     if (to) {
1120fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1121f0f7e7f7SEdgar E. Iglesias     }
1122f0f7e7f7SEdgar E. Iglesias 
1123f0f7e7f7SEdgar E. Iglesias     /* Extended MSRs are only available if addr_size > 32.  */
1124f0f7e7f7SEdgar E. Iglesias     if (dc->cpu->cfg.addr_size > 32) {
1125f0f7e7f7SEdgar E. Iglesias         /* The E-bit is encoded differently for To/From MSR.  */
1126f0f7e7f7SEdgar E. Iglesias         static const unsigned int e_bit[] = { 19, 24 };
1127f0f7e7f7SEdgar E. Iglesias 
1128f0f7e7f7SEdgar E. Iglesias         extended = extract32(dc->imm, e_bit[to], 1);
11292023e9a3SEdgar E. Iglesias     }
1130fcf5ef2aSThomas Huth 
1131fcf5ef2aSThomas Huth     /* msrclr and msrset.  */
11322023e9a3SEdgar E. Iglesias     if (clrset) {
11332023e9a3SEdgar E. Iglesias         bool clr = extract32(dc->ir, 16, 1);
1134fcf5ef2aSThomas Huth 
113556837509SEdgar E. Iglesias         if (!dc->cpu->cfg.use_msr_instr) {
1136fcf5ef2aSThomas Huth             /* nop??? */
1137fcf5ef2aSThomas Huth             return;
1138fcf5ef2aSThomas Huth         }
1139fcf5ef2aSThomas Huth 
1140bdfc1e88SEdgar E. Iglesias         if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
1141fcf5ef2aSThomas Huth             return;
1142fcf5ef2aSThomas Huth         }
1143fcf5ef2aSThomas Huth 
1144fcf5ef2aSThomas Huth         if (dc->rd)
1145fcf5ef2aSThomas Huth             msr_read(dc, cpu_R[dc->rd]);
1146fcf5ef2aSThomas Huth 
1147cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
1148cfeea807SEdgar E. Iglesias         t1 = tcg_temp_new_i32();
1149fcf5ef2aSThomas Huth         msr_read(dc, t0);
1150cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
1151fcf5ef2aSThomas Huth 
1152fcf5ef2aSThomas Huth         if (clr) {
1153cfeea807SEdgar E. Iglesias             tcg_gen_not_i32(t1, t1);
1154cfeea807SEdgar E. Iglesias             tcg_gen_and_i32(t0, t0, t1);
1155fcf5ef2aSThomas Huth         } else
1156cfeea807SEdgar E. Iglesias             tcg_gen_or_i32(t0, t0, t1);
1157fcf5ef2aSThomas Huth         msr_write(dc, t0);
1158cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
1159cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t1);
1160d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1161d4705ae0SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1162fcf5ef2aSThomas Huth         return;
1163fcf5ef2aSThomas Huth     }
1164fcf5ef2aSThomas Huth 
1165bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, to)) {
1166fcf5ef2aSThomas Huth         return;
1167fcf5ef2aSThomas Huth     }
1168fcf5ef2aSThomas Huth 
1169fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
1170fcf5ef2aSThomas Huth     /* Catch read/writes to the mmu block.  */
1171fcf5ef2aSThomas Huth     if ((sr & ~0xff) == 0x1000) {
1172f0f7e7f7SEdgar E. Iglesias         TCGv_i32 tmp_ext = tcg_const_i32(extended);
117305a9a651SEdgar E. Iglesias         TCGv_i32 tmp_sr;
117405a9a651SEdgar E. Iglesias 
1175fcf5ef2aSThomas Huth         sr &= 7;
117605a9a651SEdgar E. Iglesias         tmp_sr = tcg_const_i32(sr);
117705a9a651SEdgar E. Iglesias         if (to) {
1178f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
117905a9a651SEdgar E. Iglesias         } else {
1180f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
118105a9a651SEdgar E. Iglesias         }
118205a9a651SEdgar E. Iglesias         tcg_temp_free_i32(tmp_sr);
1183f0f7e7f7SEdgar E. Iglesias         tcg_temp_free_i32(tmp_ext);
1184fcf5ef2aSThomas Huth         return;
1185fcf5ef2aSThomas Huth     }
1186fcf5ef2aSThomas Huth #endif
1187fcf5ef2aSThomas Huth 
1188fcf5ef2aSThomas Huth     if (to) {
1189fcf5ef2aSThomas Huth         switch (sr) {
1190aa28e6d4SRichard Henderson             case SR_PC:
1191fcf5ef2aSThomas Huth                 break;
1192aa28e6d4SRichard Henderson             case SR_MSR:
1193fcf5ef2aSThomas Huth                 msr_write(dc, cpu_R[dc->ra]);
1194fcf5ef2aSThomas Huth                 break;
1195351527b7SEdgar E. Iglesias             case SR_EAR:
1196dbdb77c4SRichard Henderson                 {
1197dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
1198dbdb77c4SRichard Henderson                     tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]);
1199dbdb77c4SRichard Henderson                     tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1200dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
1201dbdb77c4SRichard Henderson                 }
1202aa28e6d4SRichard Henderson                 break;
1203351527b7SEdgar E. Iglesias             case SR_ESR:
120441ba37c4SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
120541ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
1206aa28e6d4SRichard Henderson                 break;
1207ab6dd380SEdgar E. Iglesias             case SR_FSR:
120886017ccfSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
120986017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
1210aa28e6d4SRichard Henderson                 break;
1211aa28e6d4SRichard Henderson             case SR_BTR:
1212ccf628b7SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
1213ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
1214aa28e6d4SRichard Henderson                 break;
1215aa28e6d4SRichard Henderson             case SR_EDR:
121639db007eSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
121739db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
1218fcf5ef2aSThomas Huth                 break;
1219fcf5ef2aSThomas Huth             case 0x800:
1220cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
1221cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
1222fcf5ef2aSThomas Huth                 break;
1223fcf5ef2aSThomas Huth             case 0x802:
1224cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
1225cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
1226fcf5ef2aSThomas Huth                 break;
1227fcf5ef2aSThomas Huth             default:
1228fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
1229fcf5ef2aSThomas Huth                 break;
1230fcf5ef2aSThomas Huth         }
1231fcf5ef2aSThomas Huth     } else {
1232fcf5ef2aSThomas Huth         switch (sr) {
1233aa28e6d4SRichard Henderson             case SR_PC:
1234d4705ae0SRichard Henderson                 tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1235fcf5ef2aSThomas Huth                 break;
1236aa28e6d4SRichard Henderson             case SR_MSR:
1237fcf5ef2aSThomas Huth                 msr_read(dc, cpu_R[dc->rd]);
1238fcf5ef2aSThomas Huth                 break;
1239351527b7SEdgar E. Iglesias             case SR_EAR:
1240dbdb77c4SRichard Henderson                 {
1241dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
1242dbdb77c4SRichard Henderson                     tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1243a1b48e3aSEdgar E. Iglesias                     if (extended) {
1244dbdb77c4SRichard Henderson                         tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64);
1245aa28e6d4SRichard Henderson                     } else {
1246dbdb77c4SRichard Henderson                         tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64);
1247dbdb77c4SRichard Henderson                     }
1248dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
1249a1b48e3aSEdgar E. Iglesias                 }
1250aa28e6d4SRichard Henderson                 break;
1251351527b7SEdgar E. Iglesias             case SR_ESR:
125241ba37c4SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
125341ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
1254aa28e6d4SRichard Henderson                 break;
1255351527b7SEdgar E. Iglesias             case SR_FSR:
125686017ccfSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
125786017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
1258aa28e6d4SRichard Henderson                 break;
1259351527b7SEdgar E. Iglesias             case SR_BTR:
1260ccf628b7SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
1261ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
1262aa28e6d4SRichard Henderson                 break;
12637cdae31dSTong Ho             case SR_EDR:
126439db007eSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
126539db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
1266fcf5ef2aSThomas Huth                 break;
1267fcf5ef2aSThomas Huth             case 0x800:
1268cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1269cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
1270fcf5ef2aSThomas Huth                 break;
1271fcf5ef2aSThomas Huth             case 0x802:
1272cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1273cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
1274fcf5ef2aSThomas Huth                 break;
1275351527b7SEdgar E. Iglesias             case 0x2000 ... 0x200c:
1276fcf5ef2aSThomas Huth                 rn = sr & 0xf;
1277cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1278fcf5ef2aSThomas Huth                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
1279fcf5ef2aSThomas Huth                 break;
1280fcf5ef2aSThomas Huth             default:
1281fcf5ef2aSThomas Huth                 cpu_abort(cs, "unknown mfs reg %x\n", sr);
1282fcf5ef2aSThomas Huth                 break;
1283fcf5ef2aSThomas Huth         }
1284fcf5ef2aSThomas Huth     }
1285fcf5ef2aSThomas Huth 
1286fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1287cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[0], 0);
1288fcf5ef2aSThomas Huth     }
1289fcf5ef2aSThomas Huth }
1290fcf5ef2aSThomas Huth 
1291fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc,
12929e6e1828SEdgar E. Iglesias                            TCGv_i32 d, TCGv_i32 a)
1293fcf5ef2aSThomas Huth {
1294d89b86e9SEdgar E. Iglesias     static const int mb_to_tcg_cc[] = {
1295d89b86e9SEdgar E. Iglesias         [CC_EQ] = TCG_COND_EQ,
1296d89b86e9SEdgar E. Iglesias         [CC_NE] = TCG_COND_NE,
1297d89b86e9SEdgar E. Iglesias         [CC_LT] = TCG_COND_LT,
1298d89b86e9SEdgar E. Iglesias         [CC_LE] = TCG_COND_LE,
1299d89b86e9SEdgar E. Iglesias         [CC_GE] = TCG_COND_GE,
1300d89b86e9SEdgar E. Iglesias         [CC_GT] = TCG_COND_GT,
1301d89b86e9SEdgar E. Iglesias     };
1302d89b86e9SEdgar E. Iglesias 
1303fcf5ef2aSThomas Huth     switch (cc) {
1304fcf5ef2aSThomas Huth     case CC_EQ:
1305fcf5ef2aSThomas Huth     case CC_NE:
1306fcf5ef2aSThomas Huth     case CC_LT:
1307fcf5ef2aSThomas Huth     case CC_LE:
1308fcf5ef2aSThomas Huth     case CC_GE:
1309fcf5ef2aSThomas Huth     case CC_GT:
13109e6e1828SEdgar E. Iglesias         tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
1311fcf5ef2aSThomas Huth         break;
1312fcf5ef2aSThomas Huth     default:
1313fcf5ef2aSThomas Huth         cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
1314fcf5ef2aSThomas Huth         break;
1315fcf5ef2aSThomas Huth     }
1316fcf5ef2aSThomas Huth }
1317fcf5ef2aSThomas Huth 
13180f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false)
1319fcf5ef2aSThomas Huth {
13200f96e96bSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
1321e956caf2SEdgar E. Iglesias 
13220f96e96bSRichard Henderson     tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc,
13239b158558SRichard Henderson                         cpu_btaken, zero,
1324e956caf2SEdgar E. Iglesias                         pc_true, pc_false);
1325e956caf2SEdgar E. Iglesias 
13260f96e96bSRichard Henderson     tcg_temp_free_i32(zero);
1327fcf5ef2aSThomas Huth }
1328fcf5ef2aSThomas Huth 
1329f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc)
1330f91c60f0SEdgar E. Iglesias {
1331f91c60f0SEdgar E. Iglesias     dc->delayed_branch = 2;
1332f91c60f0SEdgar E. Iglesias     dc->tb_flags |= D_FLAG;
13337b34f45fSRichard Henderson     if (dc->type_b && (dc->tb_flags & IMM_FLAG)) {
13347b34f45fSRichard Henderson         dc->tb_flags |= BIMM_FLAG;
13357b34f45fSRichard Henderson     }
1336f91c60f0SEdgar E. Iglesias }
1337f91c60f0SEdgar E. Iglesias 
1338fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc)
1339fcf5ef2aSThomas Huth {
1340fcf5ef2aSThomas Huth     unsigned int cc;
1341fcf5ef2aSThomas Huth     unsigned int dslot;
1342fcf5ef2aSThomas Huth 
1343fcf5ef2aSThomas Huth     cc = EXTRACT_FIELD(dc->ir, 21, 23);
1344fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 25);
1345fcf5ef2aSThomas Huth 
1346fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1347fcf5ef2aSThomas Huth     if (dslot) {
1348f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1349fcf5ef2aSThomas Huth     }
1350fcf5ef2aSThomas Huth 
1351d7ecb757SRichard Henderson     if (dc->type_b) {
1352fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT_CC;
1353d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1354d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1355fcf5ef2aSThomas Huth     } else {
1356fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
1357d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1358fcf5ef2aSThomas Huth     }
13599b158558SRichard Henderson     eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]);
1360fcf5ef2aSThomas Huth }
1361fcf5ef2aSThomas Huth 
1362fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc)
1363fcf5ef2aSThomas Huth {
1364fcf5ef2aSThomas Huth     unsigned int dslot, link, abs, mbar;
1365fcf5ef2aSThomas Huth 
1366fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 20);
1367fcf5ef2aSThomas Huth     abs = dc->ir & (1 << 19);
1368fcf5ef2aSThomas Huth     link = dc->ir & (1 << 18);
1369fcf5ef2aSThomas Huth 
1370fcf5ef2aSThomas Huth     /* Memory barrier.  */
1371fcf5ef2aSThomas Huth     mbar = (dc->ir >> 16) & 31;
1372fcf5ef2aSThomas Huth     if (mbar == 2 && dc->imm == 4) {
1373badcbf9dSEdgar E. Iglesias         uint16_t mbar_imm = dc->rd;
1374badcbf9dSEdgar E. Iglesias 
13753f172744SEdgar E. Iglesias         /* Data access memory barrier.  */
13763f172744SEdgar E. Iglesias         if ((mbar_imm & 2) == 0) {
13773f172744SEdgar E. Iglesias             tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
13783f172744SEdgar E. Iglesias         }
13793f172744SEdgar E. Iglesias 
1380fcf5ef2aSThomas Huth         /* mbar IMM & 16 decodes to sleep.  */
1381badcbf9dSEdgar E. Iglesias         if (mbar_imm & 16) {
138241ba37c4SRichard Henderson             TCGv_i32 tmp_1;
1383fcf5ef2aSThomas Huth 
1384b4919e7dSEdgar E. Iglesias             if (trap_userspace(dc, true)) {
1385b4919e7dSEdgar E. Iglesias                 /* Sleep is a privileged instruction.  */
1386b4919e7dSEdgar E. Iglesias                 return;
1387b4919e7dSEdgar E. Iglesias             }
1388b4919e7dSEdgar E. Iglesias 
1389fcf5ef2aSThomas Huth             t_sync_flags(dc);
139041ba37c4SRichard Henderson 
139141ba37c4SRichard Henderson             tmp_1 = tcg_const_i32(1);
1392fcf5ef2aSThomas Huth             tcg_gen_st_i32(tmp_1, cpu_env,
1393fcf5ef2aSThomas Huth                            -offsetof(MicroBlazeCPU, env)
1394fcf5ef2aSThomas Huth                            +offsetof(CPUState, halted));
1395fcf5ef2aSThomas Huth             tcg_temp_free_i32(tmp_1);
139641ba37c4SRichard Henderson 
1397d4705ae0SRichard Henderson             tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
139841ba37c4SRichard Henderson 
139941ba37c4SRichard Henderson             gen_raise_exception(dc, EXCP_HLT);
1400fcf5ef2aSThomas Huth             return;
1401fcf5ef2aSThomas Huth         }
1402fcf5ef2aSThomas Huth         /* Break the TB.  */
1403fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1404fcf5ef2aSThomas Huth         return;
1405fcf5ef2aSThomas Huth     }
1406fcf5ef2aSThomas Huth 
1407d7ecb757SRichard Henderson     if (abs && link && !dslot) {
1408d7ecb757SRichard Henderson         if (dc->type_b) {
1409d7ecb757SRichard Henderson             /* BRKI */
1410d7ecb757SRichard Henderson             uint32_t imm = dec_alu_typeb_imm(dc);
1411d7ecb757SRichard Henderson             if (trap_userspace(dc, imm != 8 && imm != 0x18)) {
1412d7ecb757SRichard Henderson                 return;
1413d7ecb757SRichard Henderson             }
1414d7ecb757SRichard Henderson         } else {
1415d7ecb757SRichard Henderson             /* BRK */
1416d7ecb757SRichard Henderson             if (trap_userspace(dc, true)) {
1417d7ecb757SRichard Henderson                 return;
1418d7ecb757SRichard Henderson             }
1419d7ecb757SRichard Henderson         }
1420d7ecb757SRichard Henderson     }
1421d7ecb757SRichard Henderson 
1422fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1423fcf5ef2aSThomas Huth     if (dslot) {
1424f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1425fcf5ef2aSThomas Huth     }
1426d7ecb757SRichard Henderson     if (link && dc->rd) {
1427d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1428d7ecb757SRichard Henderson     }
1429fcf5ef2aSThomas Huth 
1430fcf5ef2aSThomas Huth     if (abs) {
1431d7ecb757SRichard Henderson         if (dc->type_b) {
1432d7ecb757SRichard Henderson             uint32_t dest = dec_alu_typeb_imm(dc);
1433d7ecb757SRichard Henderson 
1434d7ecb757SRichard Henderson             dc->jmp = JMP_DIRECT;
1435d7ecb757SRichard Henderson             dc->jmp_pc = dest;
1436d7ecb757SRichard Henderson             tcg_gen_movi_i32(cpu_btarget, dest);
1437fcf5ef2aSThomas Huth             if (link && !dslot) {
1438d7ecb757SRichard Henderson                 switch (dest) {
1439d7ecb757SRichard Henderson                 case 8:
1440d7ecb757SRichard Henderson                 case 0x18:
1441d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_BREAK);
1442d7ecb757SRichard Henderson                     break;
1443d7ecb757SRichard Henderson                 case 0:
1444d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_DEBUG);
1445d7ecb757SRichard Henderson                     break;
1446d7ecb757SRichard Henderson                 }
1447d7ecb757SRichard Henderson             }
1448d7ecb757SRichard Henderson         } else {
1449d7ecb757SRichard Henderson             dc->jmp = JMP_INDIRECT;
1450d7ecb757SRichard Henderson             tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]);
1451d7ecb757SRichard Henderson             if (link && !dslot) {
145241ba37c4SRichard Henderson                 gen_raise_exception_sync(dc, EXCP_BREAK);
145341ba37c4SRichard Henderson             }
1454fcf5ef2aSThomas Huth         }
1455d7ecb757SRichard Henderson     } else if (dc->type_b) {
1456fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT;
1457d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1458d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1459fcf5ef2aSThomas Huth     } else {
1460d7ecb757SRichard Henderson         dc->jmp = JMP_INDIRECT;
1461d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1462d7ecb757SRichard Henderson     }
14639b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
1464fcf5ef2aSThomas Huth }
1465fcf5ef2aSThomas Huth 
1466fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc)
1467fcf5ef2aSThomas Huth {
1468cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1469cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1470cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
14713e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
14720a22f8cfSEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
14730a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_IE);
1474cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1475fcf5ef2aSThomas Huth 
1476cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1477cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1478fcf5ef2aSThomas Huth     msr_write(dc, t1);
1479cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1480cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1481fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1482fcf5ef2aSThomas Huth }
1483fcf5ef2aSThomas Huth 
1484fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc)
1485fcf5ef2aSThomas Huth {
1486cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1487cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1488cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
14893e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
14900a22f8cfSEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
1491cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1492cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1493fcf5ef2aSThomas Huth 
1494cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1495cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1496fcf5ef2aSThomas Huth     msr_write(dc, t1);
1497cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1498cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1499fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1500fcf5ef2aSThomas Huth }
1501fcf5ef2aSThomas Huth 
1502fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc)
1503fcf5ef2aSThomas Huth {
1504cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1505cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1506cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
1507fcf5ef2aSThomas Huth 
15083e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
15090a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_EE);
1510cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
1511cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1512cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1513fcf5ef2aSThomas Huth 
1514cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1515cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1516fcf5ef2aSThomas Huth     msr_write(dc, t1);
1517cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1518cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1519fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1520fcf5ef2aSThomas Huth }
1521fcf5ef2aSThomas Huth 
1522fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc)
1523fcf5ef2aSThomas Huth {
1524fcf5ef2aSThomas Huth     unsigned int b_bit, i_bit, e_bit;
1525fcf5ef2aSThomas Huth 
1526fcf5ef2aSThomas Huth     i_bit = dc->ir & (1 << 21);
1527fcf5ef2aSThomas Huth     b_bit = dc->ir & (1 << 22);
1528fcf5ef2aSThomas Huth     e_bit = dc->ir & (1 << 23);
1529fcf5ef2aSThomas Huth 
1530bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
1531bdfc1e88SEdgar E. Iglesias         return;
1532bdfc1e88SEdgar E. Iglesias     }
1533bdfc1e88SEdgar E. Iglesias 
1534f91c60f0SEdgar E. Iglesias     dec_setup_dslot(dc);
1535fcf5ef2aSThomas Huth 
1536fcf5ef2aSThomas Huth     if (i_bit) {
1537fcf5ef2aSThomas Huth         dc->tb_flags |= DRTI_FLAG;
1538fcf5ef2aSThomas Huth     } else if (b_bit) {
1539fcf5ef2aSThomas Huth         dc->tb_flags |= DRTB_FLAG;
1540fcf5ef2aSThomas Huth     } else if (e_bit) {
1541fcf5ef2aSThomas Huth         dc->tb_flags |= DRTE_FLAG;
154211105d67SRichard Henderson     }
1543fcf5ef2aSThomas Huth 
1544fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
15459b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
15460f96e96bSRichard Henderson     tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc));
1547fcf5ef2aSThomas Huth }
1548fcf5ef2aSThomas Huth 
1549fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc)
1550fcf5ef2aSThomas Huth {
15519ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, true)) {
1552fcf5ef2aSThomas Huth         return;
1553fcf5ef2aSThomas Huth     }
1554d4705ae0SRichard Henderson     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n",
1555d4705ae0SRichard Henderson                   (uint32_t)dc->base.pc_next, dc->opcode);
1556fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 1;
1557fcf5ef2aSThomas Huth }
1558fcf5ef2aSThomas Huth 
1559fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
1560fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc)
1561fcf5ef2aSThomas Huth {
1562fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1563fcf5ef2aSThomas Huth     int ctrl;
1564fcf5ef2aSThomas Huth 
1565bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
1566fcf5ef2aSThomas Huth         return;
1567fcf5ef2aSThomas Huth     }
1568fcf5ef2aSThomas Huth 
1569cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
1570fcf5ef2aSThomas Huth     if (dc->type_b) {
1571cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(t_id, dc->imm & 0xf);
1572fcf5ef2aSThomas Huth         ctrl = dc->imm >> 10;
1573fcf5ef2aSThomas Huth     } else {
1574cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
1575fcf5ef2aSThomas Huth         ctrl = dc->imm >> 5;
1576fcf5ef2aSThomas Huth     }
1577fcf5ef2aSThomas Huth 
1578cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
1579fcf5ef2aSThomas Huth 
1580fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1581fcf5ef2aSThomas Huth         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1582fcf5ef2aSThomas Huth     } else {
1583fcf5ef2aSThomas Huth         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1584fcf5ef2aSThomas Huth     }
1585cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1586cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
1587fcf5ef2aSThomas Huth }
1588fcf5ef2aSThomas Huth 
1589fcf5ef2aSThomas Huth static struct decoder_info {
1590fcf5ef2aSThomas Huth     struct {
1591fcf5ef2aSThomas Huth         uint32_t bits;
1592fcf5ef2aSThomas Huth         uint32_t mask;
1593fcf5ef2aSThomas Huth     };
1594fcf5ef2aSThomas Huth     void (*dec)(DisasContext *dc);
1595fcf5ef2aSThomas Huth } decinfo[] = {
1596fcf5ef2aSThomas Huth     {DEC_BR, dec_br},
1597fcf5ef2aSThomas Huth     {DEC_BCC, dec_bcc},
1598fcf5ef2aSThomas Huth     {DEC_RTS, dec_rts},
1599fcf5ef2aSThomas Huth     {DEC_MSR, dec_msr},
1600fcf5ef2aSThomas Huth     {DEC_STREAM, dec_stream},
1601fcf5ef2aSThomas Huth     {{0, 0}, dec_null}
1602fcf5ef2aSThomas Huth };
1603fcf5ef2aSThomas Huth 
160444d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir)
1605fcf5ef2aSThomas Huth {
1606fcf5ef2aSThomas Huth     int i;
1607fcf5ef2aSThomas Huth 
1608fcf5ef2aSThomas Huth     dc->ir = ir;
1609fcf5ef2aSThomas Huth 
1610fcf5ef2aSThomas Huth     /* bit 2 seems to indicate insn type.  */
1611fcf5ef2aSThomas Huth     dc->type_b = ir & (1 << 29);
1612fcf5ef2aSThomas Huth 
1613fcf5ef2aSThomas Huth     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1614fcf5ef2aSThomas Huth     dc->rd = EXTRACT_FIELD(ir, 21, 25);
1615fcf5ef2aSThomas Huth     dc->ra = EXTRACT_FIELD(ir, 16, 20);
1616fcf5ef2aSThomas Huth     dc->rb = EXTRACT_FIELD(ir, 11, 15);
1617fcf5ef2aSThomas Huth     dc->imm = EXTRACT_FIELD(ir, 0, 15);
1618fcf5ef2aSThomas Huth 
1619fcf5ef2aSThomas Huth     /* Large switch for all insns.  */
1620fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1621fcf5ef2aSThomas Huth         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1622fcf5ef2aSThomas Huth             decinfo[i].dec(dc);
1623fcf5ef2aSThomas Huth             break;
1624fcf5ef2aSThomas Huth         }
1625fcf5ef2aSThomas Huth     }
1626fcf5ef2aSThomas Huth }
1627fcf5ef2aSThomas Huth 
1628372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1629fcf5ef2aSThomas Huth {
1630372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1631372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1632372122e3SRichard Henderson     int bound;
1633fcf5ef2aSThomas Huth 
1634fcf5ef2aSThomas Huth     dc->cpu = cpu;
1635683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1636fcf5ef2aSThomas Huth     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
1637372122e3SRichard Henderson     dc->jmp = dc->delayed_branch ? JMP_INDIRECT : JMP_NOJMP;
1638fcf5ef2aSThomas Huth     dc->cpustate_changed = 0;
1639fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 0;
1640d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
164120800179SRichard Henderson     dc->r0 = NULL;
164220800179SRichard Henderson     dc->r0_set = false;
1643287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
1644fcf5ef2aSThomas Huth 
1645372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1646372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1647fcf5ef2aSThomas Huth }
1648fcf5ef2aSThomas Huth 
1649372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1650fcf5ef2aSThomas Huth {
1651fcf5ef2aSThomas Huth }
1652fcf5ef2aSThomas Huth 
1653372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1654372122e3SRichard Henderson {
1655683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1656683a247eSRichard Henderson 
1657683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1658683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1659372122e3SRichard Henderson }
1660fcf5ef2aSThomas Huth 
1661372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1662372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1663372122e3SRichard Henderson {
1664372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1665372122e3SRichard Henderson 
1666372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1667372122e3SRichard Henderson 
1668372122e3SRichard Henderson     /*
1669372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1670372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1671372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1672372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1673372122e3SRichard Henderson      */
1674372122e3SRichard Henderson     dc->base.pc_next += 4;
1675372122e3SRichard Henderson     return true;
1676372122e3SRichard Henderson }
1677372122e3SRichard Henderson 
1678372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1679372122e3SRichard Henderson {
1680372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1681372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
168244d1432bSRichard Henderson     uint32_t ir;
1683372122e3SRichard Henderson 
1684372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1685372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1686372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1687372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1688fcf5ef2aSThomas Huth     }
1689fcf5ef2aSThomas Huth 
1690*6f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
1691*6f9642d7SRichard Henderson 
169244d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
169344d1432bSRichard Henderson     if (!decode(dc, ir)) {
169444d1432bSRichard Henderson         old_decode(dc, ir);
169544d1432bSRichard Henderson     }
169620800179SRichard Henderson 
169720800179SRichard Henderson     if (dc->r0) {
169820800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
169920800179SRichard Henderson         dc->r0 = NULL;
170020800179SRichard Henderson         dc->r0_set = false;
170120800179SRichard Henderson     }
170220800179SRichard Henderson 
1703*6f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
1704*6f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1705d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1706372122e3SRichard Henderson     }
1707*6f9642d7SRichard Henderson 
1708*6f9642d7SRichard Henderson     dc->tb_flags &= ~IMM_FLAG;
1709*6f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1710d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1711fcf5ef2aSThomas Huth 
1712372122e3SRichard Henderson     if (dc->delayed_branch && --dc->delayed_branch == 0) {
1713372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
1714fcf5ef2aSThomas Huth             do_rti(dc);
1715372122e3SRichard Henderson         }
1716372122e3SRichard Henderson         if (dc->tb_flags & DRTB_FLAG) {
1717fcf5ef2aSThomas Huth             do_rtb(dc);
1718372122e3SRichard Henderson         }
1719372122e3SRichard Henderson         if (dc->tb_flags & DRTE_FLAG) {
1720fcf5ef2aSThomas Huth             do_rte(dc);
1721372122e3SRichard Henderson         }
1722fcf5ef2aSThomas Huth         /* Clear the delay slot flag.  */
1723fcf5ef2aSThomas Huth         dc->tb_flags &= ~D_FLAG;
1724372122e3SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1725372122e3SRichard Henderson     }
1726372122e3SRichard Henderson 
1727372122e3SRichard Henderson     /* Force an exit if the per-tb cpu state has changed.  */
1728372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
1729372122e3SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1730372122e3SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1731372122e3SRichard Henderson     }
1732372122e3SRichard Henderson }
1733372122e3SRichard Henderson 
1734372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1735372122e3SRichard Henderson {
1736372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1737372122e3SRichard Henderson 
1738372122e3SRichard Henderson     assert(!dc->abort_at_next_insn);
1739372122e3SRichard Henderson 
1740372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1741372122e3SRichard Henderson         /* We have already exited the TB. */
1742372122e3SRichard Henderson         return;
1743372122e3SRichard Henderson     }
1744372122e3SRichard Henderson 
1745372122e3SRichard Henderson     t_sync_flags(dc);
1746372122e3SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1747372122e3SRichard Henderson         sync_jmpstate(dc);
1748372122e3SRichard Henderson         dc->jmp = JMP_NOJMP;
1749372122e3SRichard Henderson     }
1750372122e3SRichard Henderson 
1751372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1752372122e3SRichard Henderson     case DISAS_TOO_MANY:
1753372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1754372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1755372122e3SRichard Henderson         return;
1756372122e3SRichard Henderson 
1757372122e3SRichard Henderson     case DISAS_UPDATE:
1758372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1759372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1760372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1761372122e3SRichard Henderson         } else {
1762372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1763372122e3SRichard Henderson         }
1764372122e3SRichard Henderson         return;
1765372122e3SRichard Henderson 
1766372122e3SRichard Henderson     case DISAS_JUMP:
1767372122e3SRichard Henderson         switch (dc->jmp) {
1768372122e3SRichard Henderson         case JMP_INDIRECT:
1769372122e3SRichard Henderson             {
1770d4705ae0SRichard Henderson                 TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next);
17710f96e96bSRichard Henderson                 eval_cond_jmp(dc, cpu_btarget, tmp_pc);
17720f96e96bSRichard Henderson                 tcg_temp_free_i32(tmp_pc);
1773372122e3SRichard Henderson 
1774372122e3SRichard Henderson                 if (unlikely(cs->singlestep_enabled)) {
1775372122e3SRichard Henderson                     gen_raise_exception(dc, EXCP_DEBUG);
1776372122e3SRichard Henderson                 } else {
1777372122e3SRichard Henderson                     tcg_gen_exit_tb(NULL, 0);
1778372122e3SRichard Henderson                 }
1779372122e3SRichard Henderson             }
1780372122e3SRichard Henderson             return;
1781372122e3SRichard Henderson 
1782372122e3SRichard Henderson         case JMP_DIRECT_CC:
1783372122e3SRichard Henderson             {
1784fcf5ef2aSThomas Huth                 TCGLabel *l1 = gen_new_label();
17859b158558SRichard Henderson                 tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1);
1786d4705ae0SRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1787fcf5ef2aSThomas Huth                 gen_set_label(l1);
1788372122e3SRichard Henderson             }
1789372122e3SRichard Henderson             /* fall through */
1790372122e3SRichard Henderson 
1791372122e3SRichard Henderson         case JMP_DIRECT:
1792fcf5ef2aSThomas Huth             gen_goto_tb(dc, 0, dc->jmp_pc);
1793372122e3SRichard Henderson             return;
1794fcf5ef2aSThomas Huth         }
1795372122e3SRichard Henderson         /* fall through */
1796fcf5ef2aSThomas Huth 
1797a2b80dbdSRichard Henderson     default:
1798a2b80dbdSRichard Henderson         g_assert_not_reached();
1799fcf5ef2aSThomas Huth     }
1800fcf5ef2aSThomas Huth }
1801fcf5ef2aSThomas Huth 
1802372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1803372122e3SRichard Henderson {
1804372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1805372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1806fcf5ef2aSThomas Huth }
1807372122e3SRichard Henderson 
1808372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1809372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1810372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1811372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1812372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1813372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1814372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1815372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1816372122e3SRichard Henderson };
1817372122e3SRichard Henderson 
1818372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1819372122e3SRichard Henderson {
1820372122e3SRichard Henderson     DisasContext dc;
1821372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1822fcf5ef2aSThomas Huth }
1823fcf5ef2aSThomas Huth 
182490c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1825fcf5ef2aSThomas Huth {
1826fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1827fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
1828fcf5ef2aSThomas Huth     int i;
1829fcf5ef2aSThomas Huth 
183090c84c56SMarkus Armbruster     if (!env) {
1831fcf5ef2aSThomas Huth         return;
183290c84c56SMarkus Armbruster     }
1833fcf5ef2aSThomas Huth 
18340f96e96bSRichard Henderson     qemu_fprintf(f, "IN: PC=%x %s\n",
183576e8187dSRichard Henderson                  env->pc, lookup_symbol(env->pc));
18366efd5599SRichard Henderson     qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " "
1837eb2022b7SRichard Henderson                  "imm=%x iflags=%x fsr=%x rbtr=%x\n",
183878e9caf2SRichard Henderson                  env->msr, env->esr, env->ear,
1839eb2022b7SRichard Henderson                  env->imm, env->iflags, env->fsr, env->btr);
18400f96e96bSRichard Henderson     qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
1841fcf5ef2aSThomas Huth                  env->btaken, env->btarget,
18422e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18432e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18442e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18452e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18462ead1b18SJoe Komlodi     for (i = 0; i < 12; i++) {
18472ead1b18SJoe Komlodi         qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]);
18482ead1b18SJoe Komlodi         if ((i + 1) % 4 == 0) {
18492ead1b18SJoe Komlodi             qemu_fprintf(f, "\n");
18502ead1b18SJoe Komlodi         }
18512ead1b18SJoe Komlodi     }
1852fcf5ef2aSThomas Huth 
18532ead1b18SJoe Komlodi     /* Registers that aren't modeled are reported as 0 */
185439db007eSRichard Henderson     qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 "
1855af20a93aSRichard Henderson                     "rtlblo=0 rtlbhi=0\n", env->edr);
18562ead1b18SJoe Komlodi     qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr);
1857fcf5ef2aSThomas Huth     for (i = 0; i < 32; i++) {
185890c84c56SMarkus Armbruster         qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1859fcf5ef2aSThomas Huth         if ((i + 1) % 4 == 0)
186090c84c56SMarkus Armbruster             qemu_fprintf(f, "\n");
1861fcf5ef2aSThomas Huth         }
186290c84c56SMarkus Armbruster     qemu_fprintf(f, "\n\n");
1863fcf5ef2aSThomas Huth }
1864fcf5ef2aSThomas Huth 
1865fcf5ef2aSThomas Huth void mb_tcg_init(void)
1866fcf5ef2aSThomas Huth {
1867480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1868480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1869fcf5ef2aSThomas Huth 
1870480d29a8SRichard Henderson     static const struct {
1871480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1872480d29a8SRichard Henderson     } i32s[] = {
1873480d29a8SRichard Henderson         R(0),  R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1874480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1875480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1876480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1877480d29a8SRichard Henderson 
1878480d29a8SRichard Henderson         SP(pc),
1879480d29a8SRichard Henderson         SP(msr),
18801074c0fbSRichard Henderson         SP(msr_c),
1881480d29a8SRichard Henderson         SP(imm),
1882480d29a8SRichard Henderson         SP(iflags),
1883480d29a8SRichard Henderson         SP(btaken),
1884480d29a8SRichard Henderson         SP(btarget),
1885480d29a8SRichard Henderson         SP(res_val),
1886480d29a8SRichard Henderson     };
1887480d29a8SRichard Henderson 
1888480d29a8SRichard Henderson #undef R
1889480d29a8SRichard Henderson #undef SP
1890480d29a8SRichard Henderson 
1891480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1892480d29a8SRichard Henderson         *i32s[i].var =
1893480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1894fcf5ef2aSThomas Huth     }
189576e8187dSRichard Henderson 
1896480d29a8SRichard Henderson     cpu_res_addr =
1897480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1898fcf5ef2aSThomas Huth }
1899fcf5ef2aSThomas Huth 
1900fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1901fcf5ef2aSThomas Huth                           target_ulong *data)
1902fcf5ef2aSThomas Huth {
190376e8187dSRichard Henderson     env->pc = data[0];
1904683a247eSRichard Henderson     env->iflags = data[1];
1905fcf5ef2aSThomas Huth }
1906