xref: /openbmc/qemu/target/microblaze/translate.c (revision ee8c7f9f9ab0c06b26e22d869cc12893e0c73bce)
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;
76683a247eSRichard Henderson     unsigned int tb_flags;
776f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
78287b1defSRichard Henderson     int mem_index;
79fcf5ef2aSThomas Huth 
80fcf5ef2aSThomas Huth #define JMP_NOJMP     0
81fcf5ef2aSThomas Huth #define JMP_DIRECT    1
82fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2
83fcf5ef2aSThomas Huth #define JMP_INDIRECT  3
84fcf5ef2aSThomas Huth     unsigned int jmp;
85fcf5ef2aSThomas Huth     uint32_t jmp_pc;
86fcf5ef2aSThomas Huth 
87fcf5ef2aSThomas Huth     int abort_at_next_insn;
88fcf5ef2aSThomas Huth } DisasContext;
89fcf5ef2aSThomas Huth 
9020800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
9120800179SRichard Henderson {
9220800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
9320800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
9420800179SRichard Henderson     }
9520800179SRichard Henderson     return x;
9620800179SRichard Henderson }
9720800179SRichard Henderson 
9844d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9944d1432bSRichard Henderson #include "decode-insns.c.inc"
10044d1432bSRichard Henderson 
101683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
102fcf5ef2aSThomas Huth {
103fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
104683a247eSRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) {
105683a247eSRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK);
106fcf5ef2aSThomas Huth     }
107fcf5ef2aSThomas Huth }
108fcf5ef2aSThomas Huth 
109d8e59c4aSRichard Henderson static inline void sync_jmpstate(DisasContext *dc)
110d8e59c4aSRichard Henderson {
111d8e59c4aSRichard Henderson     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
112d8e59c4aSRichard Henderson         if (dc->jmp == JMP_DIRECT) {
113d8e59c4aSRichard Henderson             tcg_gen_movi_i32(cpu_btaken, 1);
114d8e59c4aSRichard Henderson         }
115d8e59c4aSRichard Henderson         dc->jmp = JMP_INDIRECT;
116d8e59c4aSRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
117d8e59c4aSRichard Henderson     }
118d8e59c4aSRichard Henderson }
119d8e59c4aSRichard Henderson 
12041ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
121fcf5ef2aSThomas Huth {
122fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
123fcf5ef2aSThomas Huth 
124fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
125fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
126d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
127fcf5ef2aSThomas Huth }
128fcf5ef2aSThomas Huth 
12941ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
13041ba37c4SRichard Henderson {
13141ba37c4SRichard Henderson     t_sync_flags(dc);
132d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
13341ba37c4SRichard Henderson     gen_raise_exception(dc, index);
13441ba37c4SRichard Henderson }
13541ba37c4SRichard Henderson 
13641ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
13741ba37c4SRichard Henderson {
13841ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
13941ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
14041ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
14141ba37c4SRichard Henderson 
14241ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
14341ba37c4SRichard Henderson }
14441ba37c4SRichard Henderson 
145fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
146fcf5ef2aSThomas Huth {
147fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
148d4705ae0SRichard Henderson     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
149fcf5ef2aSThomas Huth #else
150fcf5ef2aSThomas Huth     return true;
151fcf5ef2aSThomas Huth #endif
152fcf5ef2aSThomas Huth }
153fcf5ef2aSThomas Huth 
154fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
155fcf5ef2aSThomas Huth {
156d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1570b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1580b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1590b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1600b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
1610b46fa08SRichard Henderson     } else if (use_goto_tb(dc, dest)) {
162fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1630f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
164d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
165fcf5ef2aSThomas Huth     } else {
1660f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
16707ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
168fcf5ef2aSThomas Huth     }
169d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
170fcf5ef2aSThomas Huth }
171fcf5ef2aSThomas Huth 
172bdfc1e88SEdgar E. Iglesias /*
1739ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1749ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1759ba8cd45SEdgar E. Iglesias  */
1769ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1779ba8cd45SEdgar E. Iglesias {
1782c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1795143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
18041ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1819ba8cd45SEdgar E. Iglesias     }
1829ba8cd45SEdgar E. Iglesias     return cond;
1839ba8cd45SEdgar E. Iglesias }
1849ba8cd45SEdgar E. Iglesias 
1859ba8cd45SEdgar E. Iglesias /*
186bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
187bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
188bdfc1e88SEdgar E. Iglesias  */
189bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
190bdfc1e88SEdgar E. Iglesias {
191287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
192bdfc1e88SEdgar E. Iglesias 
1932c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
19441ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
195bdfc1e88SEdgar E. Iglesias     }
196bdfc1e88SEdgar E. Iglesias     return cond_user;
197bdfc1e88SEdgar E. Iglesias }
198bdfc1e88SEdgar E. Iglesias 
199d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc)
200fcf5ef2aSThomas Huth {
201d7ecb757SRichard Henderson     tcg_debug_assert(dc->type_b);
20220800179SRichard Henderson     return typeb_imm(dc, (int16_t)dc->imm);
203fcf5ef2aSThomas Huth }
204fcf5ef2aSThomas Huth 
205cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
206fcf5ef2aSThomas Huth {
207fcf5ef2aSThomas Huth     if (dc->type_b) {
208d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc));
2099b158558SRichard Henderson         return &cpu_imm;
210d7ecb757SRichard Henderson     }
211fcf5ef2aSThomas Huth     return &cpu_R[dc->rb];
212fcf5ef2aSThomas Huth }
213fcf5ef2aSThomas Huth 
21420800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
215fcf5ef2aSThomas Huth {
21620800179SRichard Henderson     if (likely(reg != 0)) {
21720800179SRichard Henderson         return cpu_R[reg];
218fcf5ef2aSThomas Huth     }
21920800179SRichard Henderson     if (!dc->r0_set) {
22020800179SRichard Henderson         if (dc->r0 == NULL) {
22120800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
222fcf5ef2aSThomas Huth         }
22320800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
22420800179SRichard Henderson         dc->r0_set = true;
22520800179SRichard Henderson     }
22620800179SRichard Henderson     return dc->r0;
227fcf5ef2aSThomas Huth }
228fcf5ef2aSThomas Huth 
22920800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
23020800179SRichard Henderson {
23120800179SRichard Henderson     if (likely(reg != 0)) {
23220800179SRichard Henderson         return cpu_R[reg];
23320800179SRichard Henderson     }
23420800179SRichard Henderson     if (dc->r0 == NULL) {
23520800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
23620800179SRichard Henderson     }
23720800179SRichard Henderson     return dc->r0;
238fcf5ef2aSThomas Huth }
239fcf5ef2aSThomas Huth 
24020800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
24120800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
24220800179SRichard Henderson {
24320800179SRichard Henderson     TCGv_i32 rd, ra, rb;
24420800179SRichard Henderson 
24520800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24620800179SRichard Henderson         return true;
247fcf5ef2aSThomas Huth     }
24820800179SRichard Henderson 
24920800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
25020800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
25120800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
25220800179SRichard Henderson     fn(rd, ra, rb);
25320800179SRichard Henderson     return true;
25420800179SRichard Henderson }
25520800179SRichard Henderson 
25639cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
25739cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
25839cf3864SRichard Henderson {
25939cf3864SRichard Henderson     TCGv_i32 rd, ra;
26039cf3864SRichard Henderson 
26139cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
26239cf3864SRichard Henderson         return true;
26339cf3864SRichard Henderson     }
26439cf3864SRichard Henderson 
26539cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26639cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
26739cf3864SRichard Henderson     fn(rd, ra);
26839cf3864SRichard Henderson     return true;
26939cf3864SRichard Henderson }
27039cf3864SRichard Henderson 
27120800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
27220800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
27320800179SRichard Henderson {
27420800179SRichard Henderson     TCGv_i32 rd, ra;
27520800179SRichard Henderson 
27620800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
27720800179SRichard Henderson         return true;
27820800179SRichard Henderson     }
27920800179SRichard Henderson 
28020800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
28120800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
28220800179SRichard Henderson     fni(rd, ra, arg->imm);
28320800179SRichard Henderson     return true;
28420800179SRichard Henderson }
28520800179SRichard Henderson 
28620800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
28720800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
28820800179SRichard Henderson {
28920800179SRichard Henderson     TCGv_i32 rd, ra, imm;
29020800179SRichard Henderson 
29120800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
29220800179SRichard Henderson         return true;
29320800179SRichard Henderson     }
29420800179SRichard Henderson 
29520800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
29620800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
29720800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
29820800179SRichard Henderson 
29920800179SRichard Henderson     fn(rd, ra, imm);
30020800179SRichard Henderson 
30120800179SRichard Henderson     tcg_temp_free_i32(imm);
30220800179SRichard Henderson     return true;
30320800179SRichard Henderson }
30420800179SRichard Henderson 
30520800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
30620800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
30720800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
30820800179SRichard Henderson 
309607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
310607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
311607f5767SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); }
312607f5767SRichard Henderson 
31339cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
31439cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
31539cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
31639cf3864SRichard Henderson 
31739cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
31839cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
31939cf3864SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); }
32039cf3864SRichard Henderson 
32120800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
32220800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
32320800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
32420800179SRichard Henderson 
32597955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
32697955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
32797955cebSRichard Henderson     { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); }
32897955cebSRichard Henderson 
32920800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
33020800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
33120800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
33220800179SRichard Henderson 
333d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
334d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
335d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
336d5aead3dSRichard Henderson 
337d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
338d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
339d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
340d5aead3dSRichard Henderson 
34120800179SRichard Henderson /* No input carry, but output carry. */
34220800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
34320800179SRichard Henderson {
34420800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
34520800179SRichard Henderson 
34620800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
34720800179SRichard Henderson 
34820800179SRichard Henderson     tcg_temp_free_i32(zero);
34920800179SRichard Henderson }
35020800179SRichard Henderson 
35120800179SRichard Henderson /* Input and output carry. */
35220800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
35320800179SRichard Henderson {
35420800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
35520800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
35620800179SRichard Henderson 
35720800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
35820800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
35920800179SRichard Henderson 
36020800179SRichard Henderson     tcg_temp_free_i32(tmp);
36120800179SRichard Henderson     tcg_temp_free_i32(zero);
36220800179SRichard Henderson }
36320800179SRichard Henderson 
36420800179SRichard Henderson /* Input carry, but no output carry. */
36520800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
36620800179SRichard Henderson {
36720800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
36820800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
36920800179SRichard Henderson }
37020800179SRichard Henderson 
37120800179SRichard Henderson DO_TYPEA(add, true, gen_add)
37220800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
37320800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
37420800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
37520800179SRichard Henderson 
37620800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
37720800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
37820800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
37920800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
38020800179SRichard Henderson 
381cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
382cb0a0a4cSRichard Henderson {
383cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
384cb0a0a4cSRichard Henderson }
385cb0a0a4cSRichard Henderson 
386cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
387cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
388cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
389cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
390cb0a0a4cSRichard Henderson 
391081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
392081d8e02SRichard Henderson {
393081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
394081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
395081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
396081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
397081d8e02SRichard Henderson }
398081d8e02SRichard Henderson 
399081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
400081d8e02SRichard Henderson {
401081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
402081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
403081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
404081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
405081d8e02SRichard Henderson }
406081d8e02SRichard Henderson 
407081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
408081d8e02SRichard Henderson {
409081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
410081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
411081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
412081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
413081d8e02SRichard Henderson }
414081d8e02SRichard Henderson 
415081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
416081d8e02SRichard Henderson {
417081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
418081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
419081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
420081d8e02SRichard Henderson 
421081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
422081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
423081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
424081d8e02SRichard Henderson                       imm_w, imm_s);
425081d8e02SRichard Henderson     } else {
426081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
427081d8e02SRichard Henderson     }
428081d8e02SRichard Henderson }
429081d8e02SRichard Henderson 
430081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
431081d8e02SRichard Henderson {
432081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
433081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
434081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
435081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
436081d8e02SRichard Henderson 
437081d8e02SRichard Henderson     if (imm_w < imm_s) {
438081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
439081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
440081d8e02SRichard Henderson                       imm_w, imm_s);
441081d8e02SRichard Henderson     } else {
442081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
443081d8e02SRichard Henderson     }
444081d8e02SRichard Henderson }
445081d8e02SRichard Henderson 
446081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
447081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
448081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
449081d8e02SRichard Henderson 
450081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
451081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
452081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
453081d8e02SRichard Henderson 
454081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
455081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
456081d8e02SRichard Henderson 
45739cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
45839cf3864SRichard Henderson {
45939cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
46039cf3864SRichard Henderson }
46139cf3864SRichard Henderson 
46239cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
46339cf3864SRichard Henderson 
46458b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
46558b48b63SRichard Henderson {
46658b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
46758b48b63SRichard Henderson 
46858b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
46958b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
47058b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
47158b48b63SRichard Henderson     tcg_temp_free_i32(lt);
47258b48b63SRichard Henderson }
47358b48b63SRichard Henderson 
47458b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
47558b48b63SRichard Henderson {
47658b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
47758b48b63SRichard Henderson 
47858b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
47958b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
48058b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
48158b48b63SRichard Henderson     tcg_temp_free_i32(lt);
48258b48b63SRichard Henderson }
48358b48b63SRichard Henderson 
48458b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
48558b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
486a2b0b90eSRichard Henderson 
487d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
488d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
489d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
490d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
491d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
492d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
493d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
494d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
495d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
496d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
497d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
498d5aead3dSRichard Henderson 
499d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
500d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
501d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
502d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
503d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
504d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
505d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
506d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
507d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
508d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
509d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
510d5aead3dSRichard Henderson 
511d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
512d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
513d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
514d5aead3dSRichard Henderson 
515d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
516d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
517d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
518d5aead3dSRichard Henderson 
519d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
520b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
521b1354342SRichard Henderson {
522b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
523b1354342SRichard Henderson }
524b1354342SRichard Henderson 
525b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
526b1354342SRichard Henderson {
527b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
528b1354342SRichard Henderson }
529b1354342SRichard Henderson 
530b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
531b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
532b1354342SRichard Henderson 
533e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
534e64b2e5cSRichard Henderson {
535e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
536e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
5376f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
538e64b2e5cSRichard Henderson     return true;
539e64b2e5cSRichard Henderson }
540e64b2e5cSRichard Henderson 
54197955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
54297955cebSRichard Henderson {
54397955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
54497955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
54597955cebSRichard Henderson     tcg_temp_free_i32(tmp);
54697955cebSRichard Henderson }
54797955cebSRichard Henderson 
54897955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
54997955cebSRichard Henderson {
55097955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
55197955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
55297955cebSRichard Henderson     tcg_temp_free_i32(tmp);
55397955cebSRichard Henderson }
55497955cebSRichard Henderson 
55597955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
55697955cebSRichard Henderson {
55797955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
55897955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
55997955cebSRichard Henderson     tcg_temp_free_i32(tmp);
56097955cebSRichard Henderson }
56197955cebSRichard Henderson 
56297955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
56397955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
56497955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
56597955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
56697955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
56797955cebSRichard Henderson 
568cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
569cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
570cb0a0a4cSRichard Henderson 
571607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
572607f5767SRichard Henderson {
573607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
574607f5767SRichard Henderson }
575607f5767SRichard Henderson 
576607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
577607f5767SRichard Henderson {
578607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
579607f5767SRichard Henderson }
580607f5767SRichard Henderson 
581607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
582607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
583607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
584607f5767SRichard Henderson 
585a2b0b90eSRichard Henderson /* No input carry, but output carry. */
586a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
587a2b0b90eSRichard Henderson {
588a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
589a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
590a2b0b90eSRichard Henderson }
591a2b0b90eSRichard Henderson 
592a2b0b90eSRichard Henderson /* Input and output carry. */
593a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
594a2b0b90eSRichard Henderson {
595a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
596a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
597a2b0b90eSRichard Henderson 
598a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
599a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
600a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
601a2b0b90eSRichard Henderson 
602a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
603a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
604a2b0b90eSRichard Henderson }
605a2b0b90eSRichard Henderson 
606a2b0b90eSRichard Henderson /* No input or output carry. */
607a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
608a2b0b90eSRichard Henderson {
609a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
610a2b0b90eSRichard Henderson }
611a2b0b90eSRichard Henderson 
612a2b0b90eSRichard Henderson /* Input carry, no output carry. */
613a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
614a2b0b90eSRichard Henderson {
615a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
616a2b0b90eSRichard Henderson 
617a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
618a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
619a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
620a2b0b90eSRichard Henderson 
621a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
622a2b0b90eSRichard Henderson }
623a2b0b90eSRichard Henderson 
624a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
625a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
626a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
627a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
628a2b0b90eSRichard Henderson 
629a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
630a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
631a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
632a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
633a2b0b90eSRichard Henderson 
63439cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
63539cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
63639cf3864SRichard Henderson 
63739cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
63839cf3864SRichard Henderson {
63939cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
64039cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
64139cf3864SRichard Henderson }
64239cf3864SRichard Henderson 
64339cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
64439cf3864SRichard Henderson {
64539cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
64639cf3864SRichard Henderson 
64739cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
64839cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
64939cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
65039cf3864SRichard Henderson 
65139cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
65239cf3864SRichard Henderson }
65339cf3864SRichard Henderson 
65439cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
65539cf3864SRichard Henderson {
65639cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
65739cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
65839cf3864SRichard Henderson }
65939cf3864SRichard Henderson 
66039cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
66139cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
66239cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
66339cf3864SRichard Henderson 
66439cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
66539cf3864SRichard Henderson {
66639cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
66739cf3864SRichard Henderson }
66839cf3864SRichard Henderson 
66939cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
67039cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
67139cf3864SRichard Henderson 
67239cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
67339cf3864SRichard Henderson {
67439cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
67539cf3864SRichard Henderson     trap_userspace(dc, true);
67639cf3864SRichard Henderson     return true;
67739cf3864SRichard Henderson }
67839cf3864SRichard Henderson 
679cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
680cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
681cb0a0a4cSRichard Henderson 
682d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
683d8e59c4aSRichard Henderson {
684d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
685d8e59c4aSRichard Henderson 
686d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
687d8e59c4aSRichard Henderson     if (ra && rb) {
688d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
689d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
690d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
691d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
692d8e59c4aSRichard Henderson     } else if (ra) {
693d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
694d8e59c4aSRichard Henderson     } else if (rb) {
695d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
696d8e59c4aSRichard Henderson     } else {
697d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
698d8e59c4aSRichard Henderson     }
699d8e59c4aSRichard Henderson 
700d8e59c4aSRichard Henderson     if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) {
701d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
702d8e59c4aSRichard Henderson     }
703d8e59c4aSRichard Henderson     return ret;
704d8e59c4aSRichard Henderson }
705d8e59c4aSRichard Henderson 
706d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
707d8e59c4aSRichard Henderson {
708d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
709d8e59c4aSRichard Henderson 
710d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
711d8e59c4aSRichard Henderson     if (ra) {
712d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
713d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
714d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
715d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
716d8e59c4aSRichard Henderson     } else {
717d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
718d8e59c4aSRichard Henderson     }
719d8e59c4aSRichard Henderson 
720d8e59c4aSRichard Henderson     if (ra == 1 && dc->cpu->cfg.stackprot) {
721d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
722d8e59c4aSRichard Henderson     }
723d8e59c4aSRichard Henderson     return ret;
724d8e59c4aSRichard Henderson }
725d8e59c4aSRichard Henderson 
726d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
727d8e59c4aSRichard Henderson {
728d8e59c4aSRichard Henderson     int addr_size = dc->cpu->cfg.addr_size;
729d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
730d8e59c4aSRichard Henderson 
731d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
732d8e59c4aSRichard Henderson         if (rb) {
733d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
734d8e59c4aSRichard Henderson         } else {
735d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
736d8e59c4aSRichard Henderson         }
737d8e59c4aSRichard Henderson     } else {
738d8e59c4aSRichard Henderson         if (rb) {
739d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
740d8e59c4aSRichard Henderson         } else {
741d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
742d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
743d8e59c4aSRichard Henderson         }
744d8e59c4aSRichard Henderson         if (addr_size < 64) {
745d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
746d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
747d8e59c4aSRichard Henderson         }
748d8e59c4aSRichard Henderson     }
749d8e59c4aSRichard Henderson     return ret;
750d8e59c4aSRichard Henderson }
751d8e59c4aSRichard Henderson 
752ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
753ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
754ab0c8d0fSRichard Henderson {
755ab0c8d0fSRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
756ab0c8d0fSRichard Henderson 
757ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
758ab0c8d0fSRichard Henderson     iflags |= rd << 5;
759ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
760ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
761ab0c8d0fSRichard Henderson 
762ab0c8d0fSRichard Henderson     tcg_set_insn_start_param(dc->insn_start, 1, iflags);
763ab0c8d0fSRichard Henderson }
764ab0c8d0fSRichard Henderson 
765d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
766d8e59c4aSRichard Henderson                     int mem_index, bool rev)
767d8e59c4aSRichard Henderson {
768d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
769d8e59c4aSRichard Henderson 
770d8e59c4aSRichard Henderson     /*
771d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
772d8e59c4aSRichard Henderson      *
773d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
774d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
775d8e59c4aSRichard Henderson      */
776d8e59c4aSRichard Henderson     if (rev) {
777d8e59c4aSRichard Henderson         if (size > MO_8) {
778d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
779d8e59c4aSRichard Henderson         }
780d8e59c4aSRichard Henderson         if (size < MO_32) {
781d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
782d8e59c4aSRichard Henderson         }
783d8e59c4aSRichard Henderson     }
784d8e59c4aSRichard Henderson 
785d8e59c4aSRichard Henderson     sync_jmpstate(dc);
786d8e59c4aSRichard Henderson 
787ab0c8d0fSRichard Henderson     if (size > MO_8 &&
788ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
789ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
790ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
791ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
792d8e59c4aSRichard Henderson     }
793d8e59c4aSRichard Henderson 
794ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
795d8e59c4aSRichard Henderson 
796d8e59c4aSRichard Henderson     tcg_temp_free(addr);
797d8e59c4aSRichard Henderson     return true;
798d8e59c4aSRichard Henderson }
799d8e59c4aSRichard Henderson 
800d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
801d8e59c4aSRichard Henderson {
802d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
803d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
804d8e59c4aSRichard Henderson }
805d8e59c4aSRichard Henderson 
806d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
807d8e59c4aSRichard Henderson {
808d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
809d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
810d8e59c4aSRichard Henderson }
811d8e59c4aSRichard Henderson 
812d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
813d8e59c4aSRichard Henderson {
814d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
815d8e59c4aSRichard Henderson         return true;
816d8e59c4aSRichard Henderson     }
817d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
818d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
819d8e59c4aSRichard Henderson }
820d8e59c4aSRichard Henderson 
821d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
822d8e59c4aSRichard Henderson {
823d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
824d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
825d8e59c4aSRichard Henderson }
826d8e59c4aSRichard Henderson 
827d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
828d8e59c4aSRichard Henderson {
829d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
830d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
831d8e59c4aSRichard Henderson }
832d8e59c4aSRichard Henderson 
833d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
834d8e59c4aSRichard Henderson {
835d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
836d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
837d8e59c4aSRichard Henderson }
838d8e59c4aSRichard Henderson 
839d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
840d8e59c4aSRichard Henderson {
841d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
842d8e59c4aSRichard Henderson         return true;
843d8e59c4aSRichard Henderson     }
844d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
845d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
846d8e59c4aSRichard Henderson }
847d8e59c4aSRichard Henderson 
848d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
849d8e59c4aSRichard Henderson {
850d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
851d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
852d8e59c4aSRichard Henderson }
853d8e59c4aSRichard Henderson 
854d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
855d8e59c4aSRichard Henderson {
856d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
857d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
858d8e59c4aSRichard Henderson }
859d8e59c4aSRichard Henderson 
860d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
861d8e59c4aSRichard Henderson {
862d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
863d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
864d8e59c4aSRichard Henderson }
865d8e59c4aSRichard Henderson 
866d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
867d8e59c4aSRichard Henderson {
868d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
869d8e59c4aSRichard Henderson         return true;
870d8e59c4aSRichard Henderson     }
871d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
872d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
873d8e59c4aSRichard Henderson }
874d8e59c4aSRichard Henderson 
875d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
876d8e59c4aSRichard Henderson {
877d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
878d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
879d8e59c4aSRichard Henderson }
880d8e59c4aSRichard Henderson 
881d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
882d8e59c4aSRichard Henderson {
883d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
884d8e59c4aSRichard Henderson 
885d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
886d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
887d8e59c4aSRichard Henderson 
888d8e59c4aSRichard Henderson     sync_jmpstate(dc);
889d8e59c4aSRichard Henderson 
890d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
891d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
892d8e59c4aSRichard Henderson     tcg_temp_free(addr);
893d8e59c4aSRichard Henderson 
894d8e59c4aSRichard Henderson     if (arg->rd) {
895d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
896d8e59c4aSRichard Henderson     }
897d8e59c4aSRichard Henderson 
898d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
899d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
900d8e59c4aSRichard Henderson     return true;
901d8e59c4aSRichard Henderson }
902d8e59c4aSRichard Henderson 
903d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
904d8e59c4aSRichard Henderson                      int mem_index, bool rev)
905d8e59c4aSRichard Henderson {
906d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
907d8e59c4aSRichard Henderson 
908d8e59c4aSRichard Henderson     /*
909d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
910d8e59c4aSRichard Henderson      *
911d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
912d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
913d8e59c4aSRichard Henderson      */
914d8e59c4aSRichard Henderson     if (rev) {
915d8e59c4aSRichard Henderson         if (size > MO_8) {
916d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
917d8e59c4aSRichard Henderson         }
918d8e59c4aSRichard Henderson         if (size < MO_32) {
919d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
920d8e59c4aSRichard Henderson         }
921d8e59c4aSRichard Henderson     }
922d8e59c4aSRichard Henderson 
923d8e59c4aSRichard Henderson     sync_jmpstate(dc);
924d8e59c4aSRichard Henderson 
925ab0c8d0fSRichard Henderson     if (size > MO_8 &&
926ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
927ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
928ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
929ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
930d8e59c4aSRichard Henderson     }
931d8e59c4aSRichard Henderson 
932ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
933ab0c8d0fSRichard Henderson 
934d8e59c4aSRichard Henderson     tcg_temp_free(addr);
935d8e59c4aSRichard Henderson     return true;
936d8e59c4aSRichard Henderson }
937d8e59c4aSRichard Henderson 
938d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
939d8e59c4aSRichard Henderson {
940d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
941d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
942d8e59c4aSRichard Henderson }
943d8e59c4aSRichard Henderson 
944d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
945d8e59c4aSRichard Henderson {
946d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
947d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
948d8e59c4aSRichard Henderson }
949d8e59c4aSRichard Henderson 
950d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
951d8e59c4aSRichard Henderson {
952d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
953d8e59c4aSRichard Henderson         return true;
954d8e59c4aSRichard Henderson     }
955d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
956d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
957d8e59c4aSRichard Henderson }
958d8e59c4aSRichard Henderson 
959d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
960d8e59c4aSRichard Henderson {
961d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
962d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
963d8e59c4aSRichard Henderson }
964d8e59c4aSRichard Henderson 
965d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
966d8e59c4aSRichard Henderson {
967d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
968d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
969d8e59c4aSRichard Henderson }
970d8e59c4aSRichard Henderson 
971d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
972d8e59c4aSRichard Henderson {
973d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
974d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
975d8e59c4aSRichard Henderson }
976d8e59c4aSRichard Henderson 
977d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
978d8e59c4aSRichard Henderson {
979d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
980d8e59c4aSRichard Henderson         return true;
981d8e59c4aSRichard Henderson     }
982d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
983d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
984d8e59c4aSRichard Henderson }
985d8e59c4aSRichard Henderson 
986d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
987d8e59c4aSRichard Henderson {
988d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
989d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
990d8e59c4aSRichard Henderson }
991d8e59c4aSRichard Henderson 
992d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
993d8e59c4aSRichard Henderson {
994d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
995d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
996d8e59c4aSRichard Henderson }
997d8e59c4aSRichard Henderson 
998d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
999d8e59c4aSRichard Henderson {
1000d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1001d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
1002d8e59c4aSRichard Henderson }
1003d8e59c4aSRichard Henderson 
1004d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
1005d8e59c4aSRichard Henderson {
1006d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
1007d8e59c4aSRichard Henderson         return true;
1008d8e59c4aSRichard Henderson     }
1009d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1010d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
1011d8e59c4aSRichard Henderson }
1012d8e59c4aSRichard Henderson 
1013d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1014d8e59c4aSRichard Henderson {
1015d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1016d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1017d8e59c4aSRichard Henderson }
1018d8e59c4aSRichard Henderson 
1019d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1020d8e59c4aSRichard Henderson {
1021d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1022d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1023d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1024d8e59c4aSRichard Henderson     TCGv_i32 tval;
1025d8e59c4aSRichard Henderson 
1026d8e59c4aSRichard Henderson     sync_jmpstate(dc);
1027d8e59c4aSRichard Henderson 
1028d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1029d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1030d8e59c4aSRichard Henderson 
1031d8e59c4aSRichard Henderson     /*
1032d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1033d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1034d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1035d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1036d8e59c4aSRichard Henderson      */
1037d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1038d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1039d8e59c4aSRichard Henderson 
1040d8e59c4aSRichard Henderson     /*
1041d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1042d8e59c4aSRichard Henderson      * the reserved location.
1043d8e59c4aSRichard Henderson      */
1044d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1045d8e59c4aSRichard Henderson 
1046d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1047d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1048d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1049d8e59c4aSRichard Henderson 
1050d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1051d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1052d8e59c4aSRichard Henderson 
1053d8e59c4aSRichard Henderson     /* Success */
1054d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1055d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1056d8e59c4aSRichard Henderson 
1057d8e59c4aSRichard Henderson     /* Failure */
1058d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1059d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1060d8e59c4aSRichard Henderson 
1061d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1062d8e59c4aSRichard Henderson 
1063d8e59c4aSRichard Henderson     /*
1064d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1065d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1066d8e59c4aSRichard Henderson      */
1067d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1068d8e59c4aSRichard Henderson     return true;
1069d8e59c4aSRichard Henderson }
1070d8e59c4aSRichard Henderson 
1071f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1072f5235314SRichard Henderson {
1073f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1074f5235314SRichard Henderson         return true;
1075f5235314SRichard Henderson     }
1076f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1077f5235314SRichard Henderson     if (arg->rd) {
1078f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1079f5235314SRichard Henderson     }
1080f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1081f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1082f5235314SRichard Henderson 
1083f5235314SRichard Henderson     dc->base.is_jmp = DISAS_UPDATE;
1084f5235314SRichard Henderson     return true;
1085f5235314SRichard Henderson }
1086f5235314SRichard Henderson 
1087f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1088f5235314SRichard Henderson {
1089f5235314SRichard Henderson     uint32_t imm = arg->imm;
1090f5235314SRichard Henderson 
1091f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1092f5235314SRichard Henderson         return true;
1093f5235314SRichard Henderson     }
1094f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1095f5235314SRichard Henderson     if (arg->rd) {
1096f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1097f5235314SRichard Henderson     }
1098f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1099f5235314SRichard Henderson 
1100f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1101f5235314SRichard Henderson     switch (imm) {
1102f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1103f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1104f5235314SRichard Henderson         break;
1105f5235314SRichard Henderson     case 0x18: /* debug trap */
1106f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1107f5235314SRichard Henderson         break;
1108f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1109f5235314SRichard Henderson         g_assert_not_reached();
1110f5235314SRichard Henderson     }
1111f5235314SRichard Henderson #else
1112f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1113f5235314SRichard Henderson 
1114f5235314SRichard Henderson     if (imm != 0x18) {
1115f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1116f5235314SRichard Henderson     }
1117f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1118f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1119f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1120f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1121f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1122f5235314SRichard Henderson     }
1123f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
1124f5235314SRichard Henderson     dc->base.is_jmp = DISAS_UPDATE;
1125f5235314SRichard Henderson #endif
1126f5235314SRichard Henderson 
1127f5235314SRichard Henderson     return true;
1128f5235314SRichard Henderson }
1129f5235314SRichard Henderson 
1130*ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1131*ee8c7f9fSRichard Henderson {
1132*ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1133*ee8c7f9fSRichard Henderson 
1134*ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1135*ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1136*ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1137*ee8c7f9fSRichard Henderson     }
1138*ee8c7f9fSRichard Henderson 
1139*ee8c7f9fSRichard Henderson     /* Sleep. */
1140*ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1141*ee8c7f9fSRichard Henderson         TCGv_i32 tmp_1;
1142*ee8c7f9fSRichard Henderson 
1143*ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1144*ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1145*ee8c7f9fSRichard Henderson             return true;
1146*ee8c7f9fSRichard Henderson         }
1147*ee8c7f9fSRichard Henderson 
1148*ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1149*ee8c7f9fSRichard Henderson 
1150*ee8c7f9fSRichard Henderson         tmp_1 = tcg_const_i32(1);
1151*ee8c7f9fSRichard Henderson         tcg_gen_st_i32(tmp_1, cpu_env,
1152*ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1153*ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1154*ee8c7f9fSRichard Henderson         tcg_temp_free_i32(tmp_1);
1155*ee8c7f9fSRichard Henderson 
1156*ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1157*ee8c7f9fSRichard Henderson 
1158*ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1159*ee8c7f9fSRichard Henderson     }
1160*ee8c7f9fSRichard Henderson 
1161*ee8c7f9fSRichard Henderson     /*
1162*ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1163*ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1164*ee8c7f9fSRichard Henderson      * code immediately.
1165*ee8c7f9fSRichard Henderson      *
1166*ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1167*ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1168*ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1169*ee8c7f9fSRichard Henderson      *
1170*ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1171*ee8c7f9fSRichard Henderson      */
1172*ee8c7f9fSRichard Henderson     dc->cpustate_changed = 1;
1173*ee8c7f9fSRichard Henderson     return true;
1174*ee8c7f9fSRichard Henderson }
1175*ee8c7f9fSRichard Henderson 
117620800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
117720800179SRichard Henderson {
117820800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
117920800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
118020800179SRichard Henderson         trap_illegal(dc, true);
118120800179SRichard Henderson         return true;
118220800179SRichard Henderson     }
118320800179SRichard Henderson     /*
118420800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
118520800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
118620800179SRichard Henderson      */
118720800179SRichard Henderson     return false;
1188fcf5ef2aSThomas Huth }
1189fcf5ef2aSThomas Huth 
11901074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1191fcf5ef2aSThomas Huth {
11921074c0fbSRichard Henderson     TCGv_i32 t;
11931074c0fbSRichard Henderson 
11941074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
11951074c0fbSRichard Henderson     t = tcg_temp_new_i32();
11961074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
11971074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
11981074c0fbSRichard Henderson     tcg_temp_free_i32(t);
1199fcf5ef2aSThomas Huth }
1200fcf5ef2aSThomas Huth 
12011074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v)
1202fcf5ef2aSThomas Huth {
1203fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
12041074c0fbSRichard Henderson 
12051074c0fbSRichard Henderson     /* Install MSR_C.  */
12061074c0fbSRichard Henderson     tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
12071074c0fbSRichard Henderson 
12081074c0fbSRichard Henderson     /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
12091074c0fbSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
1210fcf5ef2aSThomas Huth }
1211fcf5ef2aSThomas Huth 
1212fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc)
1213fcf5ef2aSThomas Huth {
1214fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
1215cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
12162023e9a3SEdgar E. Iglesias     unsigned int sr, rn;
1217f0f7e7f7SEdgar E. Iglesias     bool to, clrset, extended = false;
1218fcf5ef2aSThomas Huth 
12192023e9a3SEdgar E. Iglesias     sr = extract32(dc->imm, 0, 14);
12202023e9a3SEdgar E. Iglesias     to = extract32(dc->imm, 14, 1);
12212023e9a3SEdgar E. Iglesias     clrset = extract32(dc->imm, 15, 1) == 0;
1222fcf5ef2aSThomas Huth     dc->type_b = 1;
12232023e9a3SEdgar E. Iglesias     if (to) {
1224fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1225f0f7e7f7SEdgar E. Iglesias     }
1226f0f7e7f7SEdgar E. Iglesias 
1227f0f7e7f7SEdgar E. Iglesias     /* Extended MSRs are only available if addr_size > 32.  */
1228f0f7e7f7SEdgar E. Iglesias     if (dc->cpu->cfg.addr_size > 32) {
1229f0f7e7f7SEdgar E. Iglesias         /* The E-bit is encoded differently for To/From MSR.  */
1230f0f7e7f7SEdgar E. Iglesias         static const unsigned int e_bit[] = { 19, 24 };
1231f0f7e7f7SEdgar E. Iglesias 
1232f0f7e7f7SEdgar E. Iglesias         extended = extract32(dc->imm, e_bit[to], 1);
12332023e9a3SEdgar E. Iglesias     }
1234fcf5ef2aSThomas Huth 
1235fcf5ef2aSThomas Huth     /* msrclr and msrset.  */
12362023e9a3SEdgar E. Iglesias     if (clrset) {
12372023e9a3SEdgar E. Iglesias         bool clr = extract32(dc->ir, 16, 1);
1238fcf5ef2aSThomas Huth 
123956837509SEdgar E. Iglesias         if (!dc->cpu->cfg.use_msr_instr) {
1240fcf5ef2aSThomas Huth             /* nop??? */
1241fcf5ef2aSThomas Huth             return;
1242fcf5ef2aSThomas Huth         }
1243fcf5ef2aSThomas Huth 
1244bdfc1e88SEdgar E. Iglesias         if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
1245fcf5ef2aSThomas Huth             return;
1246fcf5ef2aSThomas Huth         }
1247fcf5ef2aSThomas Huth 
1248fcf5ef2aSThomas Huth         if (dc->rd)
1249fcf5ef2aSThomas Huth             msr_read(dc, cpu_R[dc->rd]);
1250fcf5ef2aSThomas Huth 
1251cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
1252cfeea807SEdgar E. Iglesias         t1 = tcg_temp_new_i32();
1253fcf5ef2aSThomas Huth         msr_read(dc, t0);
1254cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
1255fcf5ef2aSThomas Huth 
1256fcf5ef2aSThomas Huth         if (clr) {
1257cfeea807SEdgar E. Iglesias             tcg_gen_not_i32(t1, t1);
1258cfeea807SEdgar E. Iglesias             tcg_gen_and_i32(t0, t0, t1);
1259fcf5ef2aSThomas Huth         } else
1260cfeea807SEdgar E. Iglesias             tcg_gen_or_i32(t0, t0, t1);
1261fcf5ef2aSThomas Huth         msr_write(dc, t0);
1262cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
1263cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t1);
1264d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1265d4705ae0SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1266fcf5ef2aSThomas Huth         return;
1267fcf5ef2aSThomas Huth     }
1268fcf5ef2aSThomas Huth 
1269bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, to)) {
1270fcf5ef2aSThomas Huth         return;
1271fcf5ef2aSThomas Huth     }
1272fcf5ef2aSThomas Huth 
1273fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
1274fcf5ef2aSThomas Huth     /* Catch read/writes to the mmu block.  */
1275fcf5ef2aSThomas Huth     if ((sr & ~0xff) == 0x1000) {
1276f0f7e7f7SEdgar E. Iglesias         TCGv_i32 tmp_ext = tcg_const_i32(extended);
127705a9a651SEdgar E. Iglesias         TCGv_i32 tmp_sr;
127805a9a651SEdgar E. Iglesias 
1279fcf5ef2aSThomas Huth         sr &= 7;
128005a9a651SEdgar E. Iglesias         tmp_sr = tcg_const_i32(sr);
128105a9a651SEdgar E. Iglesias         if (to) {
1282f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
128305a9a651SEdgar E. Iglesias         } else {
1284f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
128505a9a651SEdgar E. Iglesias         }
128605a9a651SEdgar E. Iglesias         tcg_temp_free_i32(tmp_sr);
1287f0f7e7f7SEdgar E. Iglesias         tcg_temp_free_i32(tmp_ext);
1288fcf5ef2aSThomas Huth         return;
1289fcf5ef2aSThomas Huth     }
1290fcf5ef2aSThomas Huth #endif
1291fcf5ef2aSThomas Huth 
1292fcf5ef2aSThomas Huth     if (to) {
1293fcf5ef2aSThomas Huth         switch (sr) {
1294aa28e6d4SRichard Henderson             case SR_PC:
1295fcf5ef2aSThomas Huth                 break;
1296aa28e6d4SRichard Henderson             case SR_MSR:
1297fcf5ef2aSThomas Huth                 msr_write(dc, cpu_R[dc->ra]);
1298fcf5ef2aSThomas Huth                 break;
1299351527b7SEdgar E. Iglesias             case SR_EAR:
1300dbdb77c4SRichard Henderson                 {
1301dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
1302dbdb77c4SRichard Henderson                     tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]);
1303dbdb77c4SRichard Henderson                     tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1304dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
1305dbdb77c4SRichard Henderson                 }
1306aa28e6d4SRichard Henderson                 break;
1307351527b7SEdgar E. Iglesias             case SR_ESR:
130841ba37c4SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
130941ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
1310aa28e6d4SRichard Henderson                 break;
1311ab6dd380SEdgar E. Iglesias             case SR_FSR:
131286017ccfSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
131386017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
1314aa28e6d4SRichard Henderson                 break;
1315aa28e6d4SRichard Henderson             case SR_BTR:
1316ccf628b7SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
1317ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
1318aa28e6d4SRichard Henderson                 break;
1319aa28e6d4SRichard Henderson             case SR_EDR:
132039db007eSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
132139db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
1322fcf5ef2aSThomas Huth                 break;
1323fcf5ef2aSThomas Huth             case 0x800:
1324cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
1325cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
1326fcf5ef2aSThomas Huth                 break;
1327fcf5ef2aSThomas Huth             case 0x802:
1328cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
1329cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
1330fcf5ef2aSThomas Huth                 break;
1331fcf5ef2aSThomas Huth             default:
1332fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
1333fcf5ef2aSThomas Huth                 break;
1334fcf5ef2aSThomas Huth         }
1335fcf5ef2aSThomas Huth     } else {
1336fcf5ef2aSThomas Huth         switch (sr) {
1337aa28e6d4SRichard Henderson             case SR_PC:
1338d4705ae0SRichard Henderson                 tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1339fcf5ef2aSThomas Huth                 break;
1340aa28e6d4SRichard Henderson             case SR_MSR:
1341fcf5ef2aSThomas Huth                 msr_read(dc, cpu_R[dc->rd]);
1342fcf5ef2aSThomas Huth                 break;
1343351527b7SEdgar E. Iglesias             case SR_EAR:
1344dbdb77c4SRichard Henderson                 {
1345dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
1346dbdb77c4SRichard Henderson                     tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1347a1b48e3aSEdgar E. Iglesias                     if (extended) {
1348dbdb77c4SRichard Henderson                         tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64);
1349aa28e6d4SRichard Henderson                     } else {
1350dbdb77c4SRichard Henderson                         tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64);
1351dbdb77c4SRichard Henderson                     }
1352dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
1353a1b48e3aSEdgar E. Iglesias                 }
1354aa28e6d4SRichard Henderson                 break;
1355351527b7SEdgar E. Iglesias             case SR_ESR:
135641ba37c4SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
135741ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
1358aa28e6d4SRichard Henderson                 break;
1359351527b7SEdgar E. Iglesias             case SR_FSR:
136086017ccfSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
136186017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
1362aa28e6d4SRichard Henderson                 break;
1363351527b7SEdgar E. Iglesias             case SR_BTR:
1364ccf628b7SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
1365ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
1366aa28e6d4SRichard Henderson                 break;
13677cdae31dSTong Ho             case SR_EDR:
136839db007eSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
136939db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
1370fcf5ef2aSThomas Huth                 break;
1371fcf5ef2aSThomas Huth             case 0x800:
1372cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1373cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
1374fcf5ef2aSThomas Huth                 break;
1375fcf5ef2aSThomas Huth             case 0x802:
1376cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1377cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
1378fcf5ef2aSThomas Huth                 break;
1379351527b7SEdgar E. Iglesias             case 0x2000 ... 0x200c:
1380fcf5ef2aSThomas Huth                 rn = sr & 0xf;
1381cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1382fcf5ef2aSThomas Huth                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
1383fcf5ef2aSThomas Huth                 break;
1384fcf5ef2aSThomas Huth             default:
1385fcf5ef2aSThomas Huth                 cpu_abort(cs, "unknown mfs reg %x\n", sr);
1386fcf5ef2aSThomas Huth                 break;
1387fcf5ef2aSThomas Huth         }
1388fcf5ef2aSThomas Huth     }
1389fcf5ef2aSThomas Huth 
1390fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1391cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[0], 0);
1392fcf5ef2aSThomas Huth     }
1393fcf5ef2aSThomas Huth }
1394fcf5ef2aSThomas Huth 
1395fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc,
13969e6e1828SEdgar E. Iglesias                            TCGv_i32 d, TCGv_i32 a)
1397fcf5ef2aSThomas Huth {
1398d89b86e9SEdgar E. Iglesias     static const int mb_to_tcg_cc[] = {
1399d89b86e9SEdgar E. Iglesias         [CC_EQ] = TCG_COND_EQ,
1400d89b86e9SEdgar E. Iglesias         [CC_NE] = TCG_COND_NE,
1401d89b86e9SEdgar E. Iglesias         [CC_LT] = TCG_COND_LT,
1402d89b86e9SEdgar E. Iglesias         [CC_LE] = TCG_COND_LE,
1403d89b86e9SEdgar E. Iglesias         [CC_GE] = TCG_COND_GE,
1404d89b86e9SEdgar E. Iglesias         [CC_GT] = TCG_COND_GT,
1405d89b86e9SEdgar E. Iglesias     };
1406d89b86e9SEdgar E. Iglesias 
1407fcf5ef2aSThomas Huth     switch (cc) {
1408fcf5ef2aSThomas Huth     case CC_EQ:
1409fcf5ef2aSThomas Huth     case CC_NE:
1410fcf5ef2aSThomas Huth     case CC_LT:
1411fcf5ef2aSThomas Huth     case CC_LE:
1412fcf5ef2aSThomas Huth     case CC_GE:
1413fcf5ef2aSThomas Huth     case CC_GT:
14149e6e1828SEdgar E. Iglesias         tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
1415fcf5ef2aSThomas Huth         break;
1416fcf5ef2aSThomas Huth     default:
1417fcf5ef2aSThomas Huth         cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
1418fcf5ef2aSThomas Huth         break;
1419fcf5ef2aSThomas Huth     }
1420fcf5ef2aSThomas Huth }
1421fcf5ef2aSThomas Huth 
14220f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false)
1423fcf5ef2aSThomas Huth {
14240f96e96bSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
1425e956caf2SEdgar E. Iglesias 
14260f96e96bSRichard Henderson     tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc,
14279b158558SRichard Henderson                         cpu_btaken, zero,
1428e956caf2SEdgar E. Iglesias                         pc_true, pc_false);
1429e956caf2SEdgar E. Iglesias 
14300f96e96bSRichard Henderson     tcg_temp_free_i32(zero);
1431fcf5ef2aSThomas Huth }
1432fcf5ef2aSThomas Huth 
1433f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc)
1434f91c60f0SEdgar E. Iglesias {
14351e521ce3SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
14367b34f45fSRichard Henderson     if (dc->type_b && (dc->tb_flags & IMM_FLAG)) {
14371e521ce3SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
14387b34f45fSRichard Henderson     }
1439f91c60f0SEdgar E. Iglesias }
1440f91c60f0SEdgar E. Iglesias 
1441fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc)
1442fcf5ef2aSThomas Huth {
1443fcf5ef2aSThomas Huth     unsigned int cc;
1444fcf5ef2aSThomas Huth     unsigned int dslot;
1445fcf5ef2aSThomas Huth 
1446fcf5ef2aSThomas Huth     cc = EXTRACT_FIELD(dc->ir, 21, 23);
1447fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 25);
1448fcf5ef2aSThomas Huth 
1449fcf5ef2aSThomas Huth     if (dslot) {
1450f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1451fcf5ef2aSThomas Huth     }
1452fcf5ef2aSThomas Huth 
1453d7ecb757SRichard Henderson     if (dc->type_b) {
1454fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT_CC;
1455d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1456d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1457fcf5ef2aSThomas Huth     } else {
1458fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
1459d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1460fcf5ef2aSThomas Huth     }
14619b158558SRichard Henderson     eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]);
1462fcf5ef2aSThomas Huth }
1463fcf5ef2aSThomas Huth 
1464fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc)
1465fcf5ef2aSThomas Huth {
1466*ee8c7f9fSRichard Henderson     unsigned int dslot, link, abs;
1467f5235314SRichard Henderson     uint32_t add_pc;
1468fcf5ef2aSThomas Huth 
1469fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 20);
1470fcf5ef2aSThomas Huth     abs = dc->ir & (1 << 19);
1471fcf5ef2aSThomas Huth     link = dc->ir & (1 << 18);
1472fcf5ef2aSThomas Huth 
1473fcf5ef2aSThomas Huth     if (dslot) {
1474f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1475fcf5ef2aSThomas Huth     }
1476d7ecb757SRichard Henderson     if (link && dc->rd) {
1477d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1478d7ecb757SRichard Henderson     }
1479fcf5ef2aSThomas Huth 
1480f5235314SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
1481d7ecb757SRichard Henderson     if (dc->type_b) {
1482d7ecb757SRichard Henderson         dc->jmp = JMP_DIRECT;
1483f5235314SRichard Henderson         dc->jmp_pc = add_pc + dec_alu_typeb_imm(dc);
1484d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1485fcf5ef2aSThomas Huth     } else {
1486d7ecb757SRichard Henderson         dc->jmp = JMP_INDIRECT;
1487f5235314SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], add_pc);
1488d7ecb757SRichard Henderson     }
14899b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
1490fcf5ef2aSThomas Huth }
1491fcf5ef2aSThomas Huth 
1492fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc)
1493fcf5ef2aSThomas Huth {
1494cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1495cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1496cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
14973e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
14980a22f8cfSEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
14990a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_IE);
1500cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1501fcf5ef2aSThomas Huth 
1502cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1503cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1504fcf5ef2aSThomas Huth     msr_write(dc, t1);
1505cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1506cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1507fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1508fcf5ef2aSThomas Huth }
1509fcf5ef2aSThomas Huth 
1510fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc)
1511fcf5ef2aSThomas Huth {
1512cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1513cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1514cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
15153e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
15160a22f8cfSEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
1517cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1518cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1519fcf5ef2aSThomas Huth 
1520cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1521cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1522fcf5ef2aSThomas Huth     msr_write(dc, t1);
1523cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1524cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1525fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1526fcf5ef2aSThomas Huth }
1527fcf5ef2aSThomas Huth 
1528fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc)
1529fcf5ef2aSThomas Huth {
1530cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1531cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1532cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
1533fcf5ef2aSThomas Huth 
15343e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
15350a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_EE);
1536cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
1537cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1538cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1539fcf5ef2aSThomas Huth 
1540cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1541cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1542fcf5ef2aSThomas Huth     msr_write(dc, t1);
1543cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1544cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1545fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1546fcf5ef2aSThomas Huth }
1547fcf5ef2aSThomas Huth 
1548fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc)
1549fcf5ef2aSThomas Huth {
1550fcf5ef2aSThomas Huth     unsigned int b_bit, i_bit, e_bit;
1551fcf5ef2aSThomas Huth 
1552fcf5ef2aSThomas Huth     i_bit = dc->ir & (1 << 21);
1553fcf5ef2aSThomas Huth     b_bit = dc->ir & (1 << 22);
1554fcf5ef2aSThomas Huth     e_bit = dc->ir & (1 << 23);
1555fcf5ef2aSThomas Huth 
1556bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
1557bdfc1e88SEdgar E. Iglesias         return;
1558bdfc1e88SEdgar E. Iglesias     }
1559bdfc1e88SEdgar E. Iglesias 
1560f91c60f0SEdgar E. Iglesias     dec_setup_dslot(dc);
1561fcf5ef2aSThomas Huth 
1562fcf5ef2aSThomas Huth     if (i_bit) {
1563fcf5ef2aSThomas Huth         dc->tb_flags |= DRTI_FLAG;
1564fcf5ef2aSThomas Huth     } else if (b_bit) {
1565fcf5ef2aSThomas Huth         dc->tb_flags |= DRTB_FLAG;
1566fcf5ef2aSThomas Huth     } else if (e_bit) {
1567fcf5ef2aSThomas Huth         dc->tb_flags |= DRTE_FLAG;
156811105d67SRichard Henderson     }
1569fcf5ef2aSThomas Huth 
1570fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
15719b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
15720f96e96bSRichard Henderson     tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc));
1573fcf5ef2aSThomas Huth }
1574fcf5ef2aSThomas Huth 
1575fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc)
1576fcf5ef2aSThomas Huth {
15779ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, true)) {
1578fcf5ef2aSThomas Huth         return;
1579fcf5ef2aSThomas Huth     }
1580d4705ae0SRichard Henderson     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n",
1581d4705ae0SRichard Henderson                   (uint32_t)dc->base.pc_next, dc->opcode);
1582fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 1;
1583fcf5ef2aSThomas Huth }
1584fcf5ef2aSThomas Huth 
1585fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
1586fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc)
1587fcf5ef2aSThomas Huth {
1588fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1589fcf5ef2aSThomas Huth     int ctrl;
1590fcf5ef2aSThomas Huth 
1591bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
1592fcf5ef2aSThomas Huth         return;
1593fcf5ef2aSThomas Huth     }
1594fcf5ef2aSThomas Huth 
1595cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
1596fcf5ef2aSThomas Huth     if (dc->type_b) {
1597cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(t_id, dc->imm & 0xf);
1598fcf5ef2aSThomas Huth         ctrl = dc->imm >> 10;
1599fcf5ef2aSThomas Huth     } else {
1600cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
1601fcf5ef2aSThomas Huth         ctrl = dc->imm >> 5;
1602fcf5ef2aSThomas Huth     }
1603fcf5ef2aSThomas Huth 
1604cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
1605fcf5ef2aSThomas Huth 
1606fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1607fcf5ef2aSThomas Huth         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1608fcf5ef2aSThomas Huth     } else {
1609fcf5ef2aSThomas Huth         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1610fcf5ef2aSThomas Huth     }
1611cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1612cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
1613fcf5ef2aSThomas Huth }
1614fcf5ef2aSThomas Huth 
1615fcf5ef2aSThomas Huth static struct decoder_info {
1616fcf5ef2aSThomas Huth     struct {
1617fcf5ef2aSThomas Huth         uint32_t bits;
1618fcf5ef2aSThomas Huth         uint32_t mask;
1619fcf5ef2aSThomas Huth     };
1620fcf5ef2aSThomas Huth     void (*dec)(DisasContext *dc);
1621fcf5ef2aSThomas Huth } decinfo[] = {
1622fcf5ef2aSThomas Huth     {DEC_BR, dec_br},
1623fcf5ef2aSThomas Huth     {DEC_BCC, dec_bcc},
1624fcf5ef2aSThomas Huth     {DEC_RTS, dec_rts},
1625fcf5ef2aSThomas Huth     {DEC_MSR, dec_msr},
1626fcf5ef2aSThomas Huth     {DEC_STREAM, dec_stream},
1627fcf5ef2aSThomas Huth     {{0, 0}, dec_null}
1628fcf5ef2aSThomas Huth };
1629fcf5ef2aSThomas Huth 
163044d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir)
1631fcf5ef2aSThomas Huth {
1632fcf5ef2aSThomas Huth     int i;
1633fcf5ef2aSThomas Huth 
1634fcf5ef2aSThomas Huth     dc->ir = ir;
1635fcf5ef2aSThomas Huth 
1636fcf5ef2aSThomas Huth     /* bit 2 seems to indicate insn type.  */
1637fcf5ef2aSThomas Huth     dc->type_b = ir & (1 << 29);
1638fcf5ef2aSThomas Huth 
1639fcf5ef2aSThomas Huth     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1640fcf5ef2aSThomas Huth     dc->rd = EXTRACT_FIELD(ir, 21, 25);
1641fcf5ef2aSThomas Huth     dc->ra = EXTRACT_FIELD(ir, 16, 20);
1642fcf5ef2aSThomas Huth     dc->rb = EXTRACT_FIELD(ir, 11, 15);
1643fcf5ef2aSThomas Huth     dc->imm = EXTRACT_FIELD(ir, 0, 15);
1644fcf5ef2aSThomas Huth 
1645fcf5ef2aSThomas Huth     /* Large switch for all insns.  */
1646fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1647fcf5ef2aSThomas Huth         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1648fcf5ef2aSThomas Huth             decinfo[i].dec(dc);
1649fcf5ef2aSThomas Huth             break;
1650fcf5ef2aSThomas Huth         }
1651fcf5ef2aSThomas Huth     }
1652fcf5ef2aSThomas Huth }
1653fcf5ef2aSThomas Huth 
1654372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1655fcf5ef2aSThomas Huth {
1656372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1657372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1658372122e3SRichard Henderson     int bound;
1659fcf5ef2aSThomas Huth 
1660fcf5ef2aSThomas Huth     dc->cpu = cpu;
1661683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
16621e521ce3SRichard Henderson     dc->jmp = dc->tb_flags & D_FLAG ? JMP_INDIRECT : JMP_NOJMP;
1663fcf5ef2aSThomas Huth     dc->cpustate_changed = 0;
1664fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 0;
1665d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
166620800179SRichard Henderson     dc->r0 = NULL;
166720800179SRichard Henderson     dc->r0_set = false;
1668287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
1669fcf5ef2aSThomas Huth 
1670372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1671372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1672fcf5ef2aSThomas Huth }
1673fcf5ef2aSThomas Huth 
1674372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1675fcf5ef2aSThomas Huth {
1676fcf5ef2aSThomas Huth }
1677fcf5ef2aSThomas Huth 
1678372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1679372122e3SRichard Henderson {
1680683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1681683a247eSRichard Henderson 
1682683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1683683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1684372122e3SRichard Henderson }
1685fcf5ef2aSThomas Huth 
1686372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1687372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1688372122e3SRichard Henderson {
1689372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1690372122e3SRichard Henderson 
1691372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1692372122e3SRichard Henderson 
1693372122e3SRichard Henderson     /*
1694372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1695372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1696372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1697372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1698372122e3SRichard Henderson      */
1699372122e3SRichard Henderson     dc->base.pc_next += 4;
1700372122e3SRichard Henderson     return true;
1701372122e3SRichard Henderson }
1702372122e3SRichard Henderson 
1703372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1704372122e3SRichard Henderson {
1705372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1706372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
170744d1432bSRichard Henderson     uint32_t ir;
1708372122e3SRichard Henderson 
1709372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1710372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1711372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1712372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1713fcf5ef2aSThomas Huth     }
1714fcf5ef2aSThomas Huth 
17156f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
17166f9642d7SRichard Henderson 
171744d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
171844d1432bSRichard Henderson     if (!decode(dc, ir)) {
171944d1432bSRichard Henderson         old_decode(dc, ir);
172044d1432bSRichard Henderson     }
172120800179SRichard Henderson 
172220800179SRichard Henderson     if (dc->r0) {
172320800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
172420800179SRichard Henderson         dc->r0 = NULL;
172520800179SRichard Henderson         dc->r0_set = false;
172620800179SRichard Henderson     }
172720800179SRichard Henderson 
17286f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
17296f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1730d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1731372122e3SRichard Henderson     }
17326f9642d7SRichard Henderson 
17331e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
17346f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1735d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1736fcf5ef2aSThomas Huth 
17371e521ce3SRichard Henderson     if (dc->jmp != JMP_NOJMP && !(dc->tb_flags & D_FLAG)) {
1738372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
1739fcf5ef2aSThomas Huth             do_rti(dc);
1740372122e3SRichard Henderson         }
1741372122e3SRichard Henderson         if (dc->tb_flags & DRTB_FLAG) {
1742fcf5ef2aSThomas Huth             do_rtb(dc);
1743372122e3SRichard Henderson         }
1744372122e3SRichard Henderson         if (dc->tb_flags & DRTE_FLAG) {
1745fcf5ef2aSThomas Huth             do_rte(dc);
1746372122e3SRichard Henderson         }
1747372122e3SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1748372122e3SRichard Henderson     }
1749372122e3SRichard Henderson 
1750372122e3SRichard Henderson     /* Force an exit if the per-tb cpu state has changed.  */
1751372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
1752372122e3SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1753372122e3SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1754372122e3SRichard Henderson     }
1755372122e3SRichard Henderson }
1756372122e3SRichard Henderson 
1757372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1758372122e3SRichard Henderson {
1759372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1760372122e3SRichard Henderson 
1761372122e3SRichard Henderson     assert(!dc->abort_at_next_insn);
1762372122e3SRichard Henderson 
1763372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1764372122e3SRichard Henderson         /* We have already exited the TB. */
1765372122e3SRichard Henderson         return;
1766372122e3SRichard Henderson     }
1767372122e3SRichard Henderson 
1768372122e3SRichard Henderson     t_sync_flags(dc);
1769372122e3SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1770372122e3SRichard Henderson         sync_jmpstate(dc);
1771372122e3SRichard Henderson         dc->jmp = JMP_NOJMP;
1772372122e3SRichard Henderson     }
1773372122e3SRichard Henderson 
1774372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1775372122e3SRichard Henderson     case DISAS_TOO_MANY:
1776372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1777372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1778372122e3SRichard Henderson         return;
1779372122e3SRichard Henderson 
1780372122e3SRichard Henderson     case DISAS_UPDATE:
1781372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1782372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1783372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1784372122e3SRichard Henderson         } else {
1785372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1786372122e3SRichard Henderson         }
1787372122e3SRichard Henderson         return;
1788372122e3SRichard Henderson 
1789372122e3SRichard Henderson     case DISAS_JUMP:
1790372122e3SRichard Henderson         switch (dc->jmp) {
1791372122e3SRichard Henderson         case JMP_INDIRECT:
1792372122e3SRichard Henderson             {
1793d4705ae0SRichard Henderson                 TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next);
17940f96e96bSRichard Henderson                 eval_cond_jmp(dc, cpu_btarget, tmp_pc);
17950f96e96bSRichard Henderson                 tcg_temp_free_i32(tmp_pc);
1796372122e3SRichard Henderson 
1797372122e3SRichard Henderson                 if (unlikely(cs->singlestep_enabled)) {
1798372122e3SRichard Henderson                     gen_raise_exception(dc, EXCP_DEBUG);
1799372122e3SRichard Henderson                 } else {
1800372122e3SRichard Henderson                     tcg_gen_exit_tb(NULL, 0);
1801372122e3SRichard Henderson                 }
1802372122e3SRichard Henderson             }
1803372122e3SRichard Henderson             return;
1804372122e3SRichard Henderson 
1805372122e3SRichard Henderson         case JMP_DIRECT_CC:
1806372122e3SRichard Henderson             {
1807fcf5ef2aSThomas Huth                 TCGLabel *l1 = gen_new_label();
18089b158558SRichard Henderson                 tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1);
1809d4705ae0SRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1810fcf5ef2aSThomas Huth                 gen_set_label(l1);
1811372122e3SRichard Henderson             }
1812372122e3SRichard Henderson             /* fall through */
1813372122e3SRichard Henderson 
1814372122e3SRichard Henderson         case JMP_DIRECT:
1815fcf5ef2aSThomas Huth             gen_goto_tb(dc, 0, dc->jmp_pc);
1816372122e3SRichard Henderson             return;
1817fcf5ef2aSThomas Huth         }
1818372122e3SRichard Henderson         /* fall through */
1819fcf5ef2aSThomas Huth 
1820a2b80dbdSRichard Henderson     default:
1821a2b80dbdSRichard Henderson         g_assert_not_reached();
1822fcf5ef2aSThomas Huth     }
1823fcf5ef2aSThomas Huth }
1824fcf5ef2aSThomas Huth 
1825372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1826372122e3SRichard Henderson {
1827372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1828372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1829fcf5ef2aSThomas Huth }
1830372122e3SRichard Henderson 
1831372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1832372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1833372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1834372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1835372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1836372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1837372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1838372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1839372122e3SRichard Henderson };
1840372122e3SRichard Henderson 
1841372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1842372122e3SRichard Henderson {
1843372122e3SRichard Henderson     DisasContext dc;
1844372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1845fcf5ef2aSThomas Huth }
1846fcf5ef2aSThomas Huth 
184790c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1848fcf5ef2aSThomas Huth {
1849fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1850fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
18510c3da918SRichard Henderson     uint32_t iflags;
1852fcf5ef2aSThomas Huth     int i;
1853fcf5ef2aSThomas Huth 
18540c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18550c3da918SRichard Henderson                  env->pc, env->msr,
18562e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18572e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18582e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18592e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18600c3da918SRichard Henderson 
18610c3da918SRichard Henderson     iflags = env->iflags;
18620c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18630c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18640c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18652ead1b18SJoe Komlodi     }
18660c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18670c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18680c3da918SRichard Henderson     }
18690c3da918SRichard Henderson     if (iflags & D_FLAG) {
18700c3da918SRichard Henderson         qemu_fprintf(f, " D(btaken=%d btarget=0x%08x)",
18710c3da918SRichard Henderson                      env->btaken, env->btarget);
18720c3da918SRichard Henderson     }
18730c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18740c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18750c3da918SRichard Henderson     }
18760c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18770c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18780c3da918SRichard Henderson     }
18790c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18800c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18810c3da918SRichard Henderson     }
18820c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18830c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18842ead1b18SJoe Komlodi     }
1885fcf5ef2aSThomas Huth 
18860c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
18870c3da918SRichard Henderson                  "ear=0x%016" PRIx64 " slr=0x%x shr=0x%x\n",
18880c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18890c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18900c3da918SRichard Henderson 
18910c3da918SRichard Henderson     for (i = 0; i < 12; i++) {
18920c3da918SRichard Henderson         qemu_fprintf(f, "rpvr%-2d=%08x%c",
18930c3da918SRichard Henderson                      i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' ');
1894fcf5ef2aSThomas Huth     }
18950c3da918SRichard Henderson 
18960c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18970c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18980c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18990c3da918SRichard Henderson     }
19000c3da918SRichard Henderson     qemu_fprintf(f, "\n");
1901fcf5ef2aSThomas Huth }
1902fcf5ef2aSThomas Huth 
1903fcf5ef2aSThomas Huth void mb_tcg_init(void)
1904fcf5ef2aSThomas Huth {
1905480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1906480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1907fcf5ef2aSThomas Huth 
1908480d29a8SRichard Henderson     static const struct {
1909480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1910480d29a8SRichard Henderson     } i32s[] = {
1911480d29a8SRichard Henderson         R(0),  R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1912480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1913480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1914480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1915480d29a8SRichard Henderson 
1916480d29a8SRichard Henderson         SP(pc),
1917480d29a8SRichard Henderson         SP(msr),
19181074c0fbSRichard Henderson         SP(msr_c),
1919480d29a8SRichard Henderson         SP(imm),
1920480d29a8SRichard Henderson         SP(iflags),
1921480d29a8SRichard Henderson         SP(btaken),
1922480d29a8SRichard Henderson         SP(btarget),
1923480d29a8SRichard Henderson         SP(res_val),
1924480d29a8SRichard Henderson     };
1925480d29a8SRichard Henderson 
1926480d29a8SRichard Henderson #undef R
1927480d29a8SRichard Henderson #undef SP
1928480d29a8SRichard Henderson 
1929480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1930480d29a8SRichard Henderson         *i32s[i].var =
1931480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1932fcf5ef2aSThomas Huth     }
193376e8187dSRichard Henderson 
1934480d29a8SRichard Henderson     cpu_res_addr =
1935480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1936fcf5ef2aSThomas Huth }
1937fcf5ef2aSThomas Huth 
1938fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1939fcf5ef2aSThomas Huth                           target_ulong *data)
1940fcf5ef2aSThomas Huth {
194176e8187dSRichard Henderson     env->pc = data[0];
1942683a247eSRichard Henderson     env->iflags = data[1];
1943fcf5ef2aSThomas Huth }
1944