xref: /openbmc/qemu/target/microblaze/translate.c (revision d8e59c4a6f888a8711af293d9ce2bb9609973748)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  Xilinx MicroBlaze emulation for qemu: main translation routines.
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2009 Edgar E. Iglesias.
5fcf5ef2aSThomas Huth  *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
10fcf5ef2aSThomas Huth  * version 2 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth  */
20fcf5ef2aSThomas Huth 
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "disas/disas.h"
24fcf5ef2aSThomas Huth #include "exec/exec-all.h"
25dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg-op.h"
26fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
27fcf5ef2aSThomas Huth #include "microblaze-decode.h"
28fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h"
29fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
3077fc6f5eSLluís Vilanova #include "exec/translator.h"
3190c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
32fcf5ef2aSThomas Huth 
33fcf5ef2aSThomas Huth #include "trace-tcg.h"
34fcf5ef2aSThomas Huth #include "exec/log.h"
35fcf5ef2aSThomas Huth 
36fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
37fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
38fcf5ef2aSThomas Huth 
3977fc6f5eSLluís Vilanova /* is_jmp field values */
4077fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
4177fc6f5eSLluís Vilanova #define DISAS_UPDATE  DISAS_TARGET_1 /* cpu state was modified dynamically */
4277fc6f5eSLluís Vilanova 
43cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
440f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
453e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
461074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
479b158558SRichard Henderson static TCGv_i32 cpu_imm;
489b158558SRichard Henderson static TCGv_i32 cpu_btaken;
490f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
509b158558SRichard Henderson static TCGv_i32 cpu_iflags;
519b158558SRichard Henderson static TCGv cpu_res_addr;
529b158558SRichard Henderson static TCGv_i32 cpu_res_val;
53fcf5ef2aSThomas Huth 
54fcf5ef2aSThomas Huth #include "exec/gen-icount.h"
55fcf5ef2aSThomas Huth 
56fcf5ef2aSThomas Huth /* This is the state at translation time.  */
57fcf5ef2aSThomas Huth typedef struct DisasContext {
58d4705ae0SRichard Henderson     DisasContextBase base;
59fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu;
60fcf5ef2aSThomas Huth 
6120800179SRichard Henderson     TCGv_i32 r0;
6220800179SRichard Henderson     bool r0_set;
6320800179SRichard Henderson 
64fcf5ef2aSThomas Huth     /* Decoder.  */
65fcf5ef2aSThomas Huth     int type_b;
66fcf5ef2aSThomas Huth     uint32_t ir;
67d7ecb757SRichard Henderson     uint32_t ext_imm;
68fcf5ef2aSThomas Huth     uint8_t opcode;
69fcf5ef2aSThomas Huth     uint8_t rd, ra, rb;
70fcf5ef2aSThomas Huth     uint16_t imm;
71fcf5ef2aSThomas Huth 
72fcf5ef2aSThomas Huth     unsigned int cpustate_changed;
73fcf5ef2aSThomas Huth     unsigned int delayed_branch;
74fcf5ef2aSThomas Huth     unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
75fcf5ef2aSThomas Huth     unsigned int clear_imm;
76287b1defSRichard Henderson     int mem_index;
77fcf5ef2aSThomas Huth 
78fcf5ef2aSThomas Huth #define JMP_NOJMP     0
79fcf5ef2aSThomas Huth #define JMP_DIRECT    1
80fcf5ef2aSThomas Huth #define JMP_DIRECT_CC 2
81fcf5ef2aSThomas Huth #define JMP_INDIRECT  3
82fcf5ef2aSThomas Huth     unsigned int jmp;
83fcf5ef2aSThomas Huth     uint32_t jmp_pc;
84fcf5ef2aSThomas Huth 
85fcf5ef2aSThomas Huth     int abort_at_next_insn;
86fcf5ef2aSThomas Huth } DisasContext;
87fcf5ef2aSThomas Huth 
8820800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8920800179SRichard Henderson {
9020800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
9120800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
9220800179SRichard Henderson     }
9320800179SRichard Henderson     return x;
9420800179SRichard Henderson }
9520800179SRichard Henderson 
9644d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9744d1432bSRichard Henderson #include "decode-insns.c.inc"
9844d1432bSRichard Henderson 
99fcf5ef2aSThomas Huth static inline void t_sync_flags(DisasContext *dc)
100fcf5ef2aSThomas Huth {
101fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
102fcf5ef2aSThomas Huth     if (dc->tb_flags != dc->synced_flags) {
1039b158558SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags);
104fcf5ef2aSThomas Huth         dc->synced_flags = dc->tb_flags;
105fcf5ef2aSThomas Huth     }
106fcf5ef2aSThomas Huth }
107fcf5ef2aSThomas Huth 
108*d8e59c4aSRichard Henderson static inline void sync_jmpstate(DisasContext *dc)
109*d8e59c4aSRichard Henderson {
110*d8e59c4aSRichard Henderson     if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
111*d8e59c4aSRichard Henderson         if (dc->jmp == JMP_DIRECT) {
112*d8e59c4aSRichard Henderson             tcg_gen_movi_i32(cpu_btaken, 1);
113*d8e59c4aSRichard Henderson         }
114*d8e59c4aSRichard Henderson         dc->jmp = JMP_INDIRECT;
115*d8e59c4aSRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
116*d8e59c4aSRichard Henderson     }
117*d8e59c4aSRichard Henderson }
118*d8e59c4aSRichard Henderson 
11941ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
120fcf5ef2aSThomas Huth {
121fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
122fcf5ef2aSThomas Huth 
123fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
124fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
125d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
126fcf5ef2aSThomas Huth }
127fcf5ef2aSThomas Huth 
12841ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
12941ba37c4SRichard Henderson {
13041ba37c4SRichard Henderson     t_sync_flags(dc);
131d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
13241ba37c4SRichard Henderson     gen_raise_exception(dc, index);
13341ba37c4SRichard Henderson }
13441ba37c4SRichard Henderson 
13541ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
13641ba37c4SRichard Henderson {
13741ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
13841ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
13941ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
14041ba37c4SRichard Henderson 
14141ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
14241ba37c4SRichard Henderson }
14341ba37c4SRichard Henderson 
144fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
145fcf5ef2aSThomas Huth {
146fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
147d4705ae0SRichard Henderson     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
148fcf5ef2aSThomas Huth #else
149fcf5ef2aSThomas Huth     return true;
150fcf5ef2aSThomas Huth #endif
151fcf5ef2aSThomas Huth }
152fcf5ef2aSThomas Huth 
153fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
154fcf5ef2aSThomas Huth {
155d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1560b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1570b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1580b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1590b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
1600b46fa08SRichard Henderson     } else if (use_goto_tb(dc, dest)) {
161fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1620f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
163d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
164fcf5ef2aSThomas Huth     } else {
1650f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
16607ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
167fcf5ef2aSThomas Huth     }
168d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
169fcf5ef2aSThomas Huth }
170fcf5ef2aSThomas Huth 
171bdfc1e88SEdgar E. Iglesias /*
1729ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1739ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1749ba8cd45SEdgar E. Iglesias  */
1759ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1769ba8cd45SEdgar E. Iglesias {
1772c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1785143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
17941ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1809ba8cd45SEdgar E. Iglesias     }
1819ba8cd45SEdgar E. Iglesias     return cond;
1829ba8cd45SEdgar E. Iglesias }
1839ba8cd45SEdgar E. Iglesias 
1849ba8cd45SEdgar E. Iglesias /*
185bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
186bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
187bdfc1e88SEdgar E. Iglesias  */
188bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
189bdfc1e88SEdgar E. Iglesias {
190287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
191bdfc1e88SEdgar E. Iglesias 
1922c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
19341ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
194bdfc1e88SEdgar E. Iglesias     }
195bdfc1e88SEdgar E. Iglesias     return cond_user;
196bdfc1e88SEdgar E. Iglesias }
197bdfc1e88SEdgar E. Iglesias 
198d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc)
199fcf5ef2aSThomas Huth {
200d7ecb757SRichard Henderson     tcg_debug_assert(dc->type_b);
20120800179SRichard Henderson     return typeb_imm(dc, (int16_t)dc->imm);
202fcf5ef2aSThomas Huth }
203fcf5ef2aSThomas Huth 
204cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
205fcf5ef2aSThomas Huth {
206fcf5ef2aSThomas Huth     if (dc->type_b) {
207d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc));
2089b158558SRichard Henderson         return &cpu_imm;
209d7ecb757SRichard Henderson     }
210fcf5ef2aSThomas Huth     return &cpu_R[dc->rb];
211fcf5ef2aSThomas Huth }
212fcf5ef2aSThomas Huth 
21320800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
214fcf5ef2aSThomas Huth {
21520800179SRichard Henderson     if (likely(reg != 0)) {
21620800179SRichard Henderson         return cpu_R[reg];
217fcf5ef2aSThomas Huth     }
21820800179SRichard Henderson     if (!dc->r0_set) {
21920800179SRichard Henderson         if (dc->r0 == NULL) {
22020800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
221fcf5ef2aSThomas Huth         }
22220800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
22320800179SRichard Henderson         dc->r0_set = true;
22420800179SRichard Henderson     }
22520800179SRichard Henderson     return dc->r0;
226fcf5ef2aSThomas Huth }
227fcf5ef2aSThomas Huth 
22820800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
22920800179SRichard Henderson {
23020800179SRichard Henderson     if (likely(reg != 0)) {
23120800179SRichard Henderson         return cpu_R[reg];
23220800179SRichard Henderson     }
23320800179SRichard Henderson     if (dc->r0 == NULL) {
23420800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
23520800179SRichard Henderson     }
23620800179SRichard Henderson     return dc->r0;
237fcf5ef2aSThomas Huth }
238fcf5ef2aSThomas Huth 
23920800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
24020800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
24120800179SRichard Henderson {
24220800179SRichard Henderson     TCGv_i32 rd, ra, rb;
24320800179SRichard Henderson 
24420800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24520800179SRichard Henderson         return true;
246fcf5ef2aSThomas Huth     }
24720800179SRichard Henderson 
24820800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
24920800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
25020800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
25120800179SRichard Henderson     fn(rd, ra, rb);
25220800179SRichard Henderson     return true;
25320800179SRichard Henderson }
25420800179SRichard Henderson 
25539cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
25639cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
25739cf3864SRichard Henderson {
25839cf3864SRichard Henderson     TCGv_i32 rd, ra;
25939cf3864SRichard Henderson 
26039cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
26139cf3864SRichard Henderson         return true;
26239cf3864SRichard Henderson     }
26339cf3864SRichard Henderson 
26439cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26539cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
26639cf3864SRichard Henderson     fn(rd, ra);
26739cf3864SRichard Henderson     return true;
26839cf3864SRichard Henderson }
26939cf3864SRichard Henderson 
27020800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
27120800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
27220800179SRichard Henderson {
27320800179SRichard Henderson     TCGv_i32 rd, ra;
27420800179SRichard Henderson 
27520800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
27620800179SRichard Henderson         return true;
27720800179SRichard Henderson     }
27820800179SRichard Henderson 
27920800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
28020800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
28120800179SRichard Henderson     fni(rd, ra, arg->imm);
28220800179SRichard Henderson     return true;
28320800179SRichard Henderson }
28420800179SRichard Henderson 
28520800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
28620800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
28720800179SRichard Henderson {
28820800179SRichard Henderson     TCGv_i32 rd, ra, imm;
28920800179SRichard Henderson 
29020800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
29120800179SRichard Henderson         return true;
29220800179SRichard Henderson     }
29320800179SRichard Henderson 
29420800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
29520800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
29620800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
29720800179SRichard Henderson 
29820800179SRichard Henderson     fn(rd, ra, imm);
29920800179SRichard Henderson 
30020800179SRichard Henderson     tcg_temp_free_i32(imm);
30120800179SRichard Henderson     return true;
30220800179SRichard Henderson }
30320800179SRichard Henderson 
30420800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
30520800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
30620800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
30720800179SRichard Henderson 
308607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
309607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
310607f5767SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); }
311607f5767SRichard Henderson 
31239cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
31339cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
31439cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
31539cf3864SRichard Henderson 
31639cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
31739cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
31839cf3864SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); }
31939cf3864SRichard Henderson 
32020800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
32120800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
32220800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
32320800179SRichard Henderson 
32497955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
32597955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
32697955cebSRichard Henderson     { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); }
32797955cebSRichard Henderson 
32820800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
32920800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
33020800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
33120800179SRichard Henderson 
332d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
333d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
334d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
335d5aead3dSRichard Henderson 
336d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
337d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
338d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
339d5aead3dSRichard Henderson 
34020800179SRichard Henderson /* No input carry, but output carry. */
34120800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
34220800179SRichard Henderson {
34320800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
34420800179SRichard Henderson 
34520800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
34620800179SRichard Henderson 
34720800179SRichard Henderson     tcg_temp_free_i32(zero);
34820800179SRichard Henderson }
34920800179SRichard Henderson 
35020800179SRichard Henderson /* Input and output carry. */
35120800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
35220800179SRichard Henderson {
35320800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
35420800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
35520800179SRichard Henderson 
35620800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
35720800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
35820800179SRichard Henderson 
35920800179SRichard Henderson     tcg_temp_free_i32(tmp);
36020800179SRichard Henderson     tcg_temp_free_i32(zero);
36120800179SRichard Henderson }
36220800179SRichard Henderson 
36320800179SRichard Henderson /* Input carry, but no output carry. */
36420800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
36520800179SRichard Henderson {
36620800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
36720800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
36820800179SRichard Henderson }
36920800179SRichard Henderson 
37020800179SRichard Henderson DO_TYPEA(add, true, gen_add)
37120800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
37220800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
37320800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
37420800179SRichard Henderson 
37520800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
37620800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
37720800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
37820800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
37920800179SRichard Henderson 
380cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
381cb0a0a4cSRichard Henderson {
382cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
383cb0a0a4cSRichard Henderson }
384cb0a0a4cSRichard Henderson 
385cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
386cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
387cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
388cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
389cb0a0a4cSRichard Henderson 
390081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
391081d8e02SRichard Henderson {
392081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
393081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
394081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
395081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
396081d8e02SRichard Henderson }
397081d8e02SRichard Henderson 
398081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
399081d8e02SRichard Henderson {
400081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
401081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
402081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
403081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
404081d8e02SRichard Henderson }
405081d8e02SRichard Henderson 
406081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
407081d8e02SRichard Henderson {
408081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
409081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
410081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
411081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
412081d8e02SRichard Henderson }
413081d8e02SRichard Henderson 
414081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
415081d8e02SRichard Henderson {
416081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
417081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
418081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
419081d8e02SRichard Henderson 
420081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
421081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
422081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
423081d8e02SRichard Henderson                       imm_w, imm_s);
424081d8e02SRichard Henderson     } else {
425081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
426081d8e02SRichard Henderson     }
427081d8e02SRichard Henderson }
428081d8e02SRichard Henderson 
429081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
430081d8e02SRichard Henderson {
431081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
432081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
433081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
434081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
435081d8e02SRichard Henderson 
436081d8e02SRichard Henderson     if (imm_w < imm_s) {
437081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
438081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
439081d8e02SRichard Henderson                       imm_w, imm_s);
440081d8e02SRichard Henderson     } else {
441081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
442081d8e02SRichard Henderson     }
443081d8e02SRichard Henderson }
444081d8e02SRichard Henderson 
445081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
446081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
447081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
448081d8e02SRichard Henderson 
449081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
450081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
451081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
452081d8e02SRichard Henderson 
453081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
454081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
455081d8e02SRichard Henderson 
45639cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
45739cf3864SRichard Henderson {
45839cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
45939cf3864SRichard Henderson }
46039cf3864SRichard Henderson 
46139cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
46239cf3864SRichard Henderson 
46358b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
46458b48b63SRichard Henderson {
46558b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
46658b48b63SRichard Henderson 
46758b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
46858b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
46958b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
47058b48b63SRichard Henderson     tcg_temp_free_i32(lt);
47158b48b63SRichard Henderson }
47258b48b63SRichard Henderson 
47358b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
47458b48b63SRichard Henderson {
47558b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
47658b48b63SRichard Henderson 
47758b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
47858b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
47958b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
48058b48b63SRichard Henderson     tcg_temp_free_i32(lt);
48158b48b63SRichard Henderson }
48258b48b63SRichard Henderson 
48358b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
48458b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
485a2b0b90eSRichard Henderson 
486d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
487d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
488d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
489d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
490d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
491d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
492d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
493d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
494d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
495d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
496d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
497d5aead3dSRichard Henderson 
498d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
499d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
500d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
501d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
502d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
503d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
504d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
505d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
506d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
507d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
508d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
509d5aead3dSRichard Henderson 
510d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
511d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
512d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
513d5aead3dSRichard Henderson 
514d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
515d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
516d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
517d5aead3dSRichard Henderson 
518d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
519b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
520b1354342SRichard Henderson {
521b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
522b1354342SRichard Henderson }
523b1354342SRichard Henderson 
524b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
525b1354342SRichard Henderson {
526b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
527b1354342SRichard Henderson }
528b1354342SRichard Henderson 
529b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
530b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
531b1354342SRichard Henderson 
532e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
533e64b2e5cSRichard Henderson {
534e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
535e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
536e64b2e5cSRichard Henderson     dc->tb_flags |= IMM_FLAG;
537e64b2e5cSRichard Henderson     dc->clear_imm = 0;
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 
682*d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
683*d8e59c4aSRichard Henderson {
684*d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
685*d8e59c4aSRichard Henderson 
686*d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
687*d8e59c4aSRichard Henderson     if (ra && rb) {
688*d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
689*d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
690*d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
691*d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
692*d8e59c4aSRichard Henderson     } else if (ra) {
693*d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
694*d8e59c4aSRichard Henderson     } else if (rb) {
695*d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
696*d8e59c4aSRichard Henderson     } else {
697*d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
698*d8e59c4aSRichard Henderson     }
699*d8e59c4aSRichard Henderson 
700*d8e59c4aSRichard Henderson     if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) {
701*d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
702*d8e59c4aSRichard Henderson     }
703*d8e59c4aSRichard Henderson     return ret;
704*d8e59c4aSRichard Henderson }
705*d8e59c4aSRichard Henderson 
706*d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
707*d8e59c4aSRichard Henderson {
708*d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
709*d8e59c4aSRichard Henderson 
710*d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
711*d8e59c4aSRichard Henderson     if (ra) {
712*d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
713*d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
714*d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
715*d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
716*d8e59c4aSRichard Henderson     } else {
717*d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
718*d8e59c4aSRichard Henderson     }
719*d8e59c4aSRichard Henderson 
720*d8e59c4aSRichard Henderson     if (ra == 1 && dc->cpu->cfg.stackprot) {
721*d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
722*d8e59c4aSRichard Henderson     }
723*d8e59c4aSRichard Henderson     return ret;
724*d8e59c4aSRichard Henderson }
725*d8e59c4aSRichard Henderson 
726*d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
727*d8e59c4aSRichard Henderson {
728*d8e59c4aSRichard Henderson     int addr_size = dc->cpu->cfg.addr_size;
729*d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
730*d8e59c4aSRichard Henderson 
731*d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
732*d8e59c4aSRichard Henderson         if (rb) {
733*d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
734*d8e59c4aSRichard Henderson         } else {
735*d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
736*d8e59c4aSRichard Henderson         }
737*d8e59c4aSRichard Henderson     } else {
738*d8e59c4aSRichard Henderson         if (rb) {
739*d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
740*d8e59c4aSRichard Henderson         } else {
741*d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
742*d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
743*d8e59c4aSRichard Henderson         }
744*d8e59c4aSRichard Henderson         if (addr_size < 64) {
745*d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
746*d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
747*d8e59c4aSRichard Henderson         }
748*d8e59c4aSRichard Henderson     }
749*d8e59c4aSRichard Henderson     return ret;
750*d8e59c4aSRichard Henderson }
751*d8e59c4aSRichard Henderson 
752*d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
753*d8e59c4aSRichard Henderson                     int mem_index, bool rev)
754*d8e59c4aSRichard Henderson {
755*d8e59c4aSRichard Henderson     TCGv_i32 v;
756*d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
757*d8e59c4aSRichard Henderson 
758*d8e59c4aSRichard Henderson     /*
759*d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
760*d8e59c4aSRichard Henderson      *
761*d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
762*d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
763*d8e59c4aSRichard Henderson      */
764*d8e59c4aSRichard Henderson     if (rev) {
765*d8e59c4aSRichard Henderson         if (size > MO_8) {
766*d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
767*d8e59c4aSRichard Henderson         }
768*d8e59c4aSRichard Henderson         if (size < MO_32) {
769*d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
770*d8e59c4aSRichard Henderson         }
771*d8e59c4aSRichard Henderson     }
772*d8e59c4aSRichard Henderson 
773*d8e59c4aSRichard Henderson     t_sync_flags(dc);
774*d8e59c4aSRichard Henderson     sync_jmpstate(dc);
775*d8e59c4aSRichard Henderson 
776*d8e59c4aSRichard Henderson     /*
777*d8e59c4aSRichard Henderson      * Microblaze gives MMU faults priority over faults due to
778*d8e59c4aSRichard Henderson      * unaligned addresses. That's why we speculatively do the load
779*d8e59c4aSRichard Henderson      * into v. If the load succeeds, we verify alignment of the
780*d8e59c4aSRichard Henderson      * address and if that succeeds we write into the destination reg.
781*d8e59c4aSRichard Henderson      */
782*d8e59c4aSRichard Henderson     v = tcg_temp_new_i32();
783*d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(v, addr, mem_index, mop);
784*d8e59c4aSRichard Henderson 
785*d8e59c4aSRichard Henderson     /* TODO: Convert to CPUClass::do_unaligned_access.  */
786*d8e59c4aSRichard Henderson     if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) {
787*d8e59c4aSRichard Henderson         TCGv_i32 t0 = tcg_const_i32(0);
788*d8e59c4aSRichard Henderson         TCGv_i32 treg = tcg_const_i32(rd);
789*d8e59c4aSRichard Henderson         TCGv_i32 tsize = tcg_const_i32((1 << size) - 1);
790*d8e59c4aSRichard Henderson 
791*d8e59c4aSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
792*d8e59c4aSRichard Henderson         gen_helper_memalign(cpu_env, addr, treg, t0, tsize);
793*d8e59c4aSRichard Henderson 
794*d8e59c4aSRichard Henderson         tcg_temp_free_i32(t0);
795*d8e59c4aSRichard Henderson         tcg_temp_free_i32(treg);
796*d8e59c4aSRichard Henderson         tcg_temp_free_i32(tsize);
797*d8e59c4aSRichard Henderson     }
798*d8e59c4aSRichard Henderson 
799*d8e59c4aSRichard Henderson     if (rd) {
800*d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[rd], v);
801*d8e59c4aSRichard Henderson     }
802*d8e59c4aSRichard Henderson 
803*d8e59c4aSRichard Henderson     tcg_temp_free_i32(v);
804*d8e59c4aSRichard Henderson     tcg_temp_free(addr);
805*d8e59c4aSRichard Henderson     return true;
806*d8e59c4aSRichard Henderson }
807*d8e59c4aSRichard Henderson 
808*d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
809*d8e59c4aSRichard Henderson {
810*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
811*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
812*d8e59c4aSRichard Henderson }
813*d8e59c4aSRichard Henderson 
814*d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
815*d8e59c4aSRichard Henderson {
816*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
817*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
818*d8e59c4aSRichard Henderson }
819*d8e59c4aSRichard Henderson 
820*d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
821*d8e59c4aSRichard Henderson {
822*d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
823*d8e59c4aSRichard Henderson         return true;
824*d8e59c4aSRichard Henderson     }
825*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
826*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
827*d8e59c4aSRichard Henderson }
828*d8e59c4aSRichard Henderson 
829*d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
830*d8e59c4aSRichard Henderson {
831*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
832*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
833*d8e59c4aSRichard Henderson }
834*d8e59c4aSRichard Henderson 
835*d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
836*d8e59c4aSRichard Henderson {
837*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
838*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
839*d8e59c4aSRichard Henderson }
840*d8e59c4aSRichard Henderson 
841*d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
842*d8e59c4aSRichard Henderson {
843*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
844*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
845*d8e59c4aSRichard Henderson }
846*d8e59c4aSRichard Henderson 
847*d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
848*d8e59c4aSRichard Henderson {
849*d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
850*d8e59c4aSRichard Henderson         return true;
851*d8e59c4aSRichard Henderson     }
852*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
853*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
854*d8e59c4aSRichard Henderson }
855*d8e59c4aSRichard Henderson 
856*d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
857*d8e59c4aSRichard Henderson {
858*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
859*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
860*d8e59c4aSRichard Henderson }
861*d8e59c4aSRichard Henderson 
862*d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
863*d8e59c4aSRichard Henderson {
864*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
865*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
866*d8e59c4aSRichard Henderson }
867*d8e59c4aSRichard Henderson 
868*d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
869*d8e59c4aSRichard Henderson {
870*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
871*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
872*d8e59c4aSRichard Henderson }
873*d8e59c4aSRichard Henderson 
874*d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
875*d8e59c4aSRichard Henderson {
876*d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
877*d8e59c4aSRichard Henderson         return true;
878*d8e59c4aSRichard Henderson     }
879*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
880*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
881*d8e59c4aSRichard Henderson }
882*d8e59c4aSRichard Henderson 
883*d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
884*d8e59c4aSRichard Henderson {
885*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
886*d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
887*d8e59c4aSRichard Henderson }
888*d8e59c4aSRichard Henderson 
889*d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
890*d8e59c4aSRichard Henderson {
891*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
892*d8e59c4aSRichard Henderson 
893*d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
894*d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
895*d8e59c4aSRichard Henderson 
896*d8e59c4aSRichard Henderson     t_sync_flags(dc);
897*d8e59c4aSRichard Henderson     sync_jmpstate(dc);
898*d8e59c4aSRichard Henderson 
899*d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
900*d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
901*d8e59c4aSRichard Henderson     tcg_temp_free(addr);
902*d8e59c4aSRichard Henderson 
903*d8e59c4aSRichard Henderson     if (arg->rd) {
904*d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
905*d8e59c4aSRichard Henderson     }
906*d8e59c4aSRichard Henderson 
907*d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
908*d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
909*d8e59c4aSRichard Henderson     return true;
910*d8e59c4aSRichard Henderson }
911*d8e59c4aSRichard Henderson 
912*d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
913*d8e59c4aSRichard Henderson                      int mem_index, bool rev)
914*d8e59c4aSRichard Henderson {
915*d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
916*d8e59c4aSRichard Henderson 
917*d8e59c4aSRichard Henderson     /*
918*d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
919*d8e59c4aSRichard Henderson      *
920*d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
921*d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
922*d8e59c4aSRichard Henderson      */
923*d8e59c4aSRichard Henderson     if (rev) {
924*d8e59c4aSRichard Henderson         if (size > MO_8) {
925*d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
926*d8e59c4aSRichard Henderson         }
927*d8e59c4aSRichard Henderson         if (size < MO_32) {
928*d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
929*d8e59c4aSRichard Henderson         }
930*d8e59c4aSRichard Henderson     }
931*d8e59c4aSRichard Henderson 
932*d8e59c4aSRichard Henderson     t_sync_flags(dc);
933*d8e59c4aSRichard Henderson     sync_jmpstate(dc);
934*d8e59c4aSRichard Henderson 
935*d8e59c4aSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
936*d8e59c4aSRichard Henderson 
937*d8e59c4aSRichard Henderson     /* TODO: Convert to CPUClass::do_unaligned_access.  */
938*d8e59c4aSRichard Henderson     if (dc->cpu->cfg.unaligned_exceptions && size > MO_8) {
939*d8e59c4aSRichard Henderson         TCGv_i32 t1 = tcg_const_i32(1);
940*d8e59c4aSRichard Henderson         TCGv_i32 treg = tcg_const_i32(rd);
941*d8e59c4aSRichard Henderson         TCGv_i32 tsize = tcg_const_i32((1 << size) - 1);
942*d8e59c4aSRichard Henderson 
943*d8e59c4aSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
944*d8e59c4aSRichard Henderson         /* FIXME: if the alignment is wrong, we should restore the value
945*d8e59c4aSRichard Henderson          *        in memory. One possible way to achieve this is to probe
946*d8e59c4aSRichard Henderson          *        the MMU prior to the memaccess, thay way we could put
947*d8e59c4aSRichard Henderson          *        the alignment checks in between the probe and the mem
948*d8e59c4aSRichard Henderson          *        access.
949*d8e59c4aSRichard Henderson          */
950*d8e59c4aSRichard Henderson         gen_helper_memalign(cpu_env, addr, treg, t1, tsize);
951*d8e59c4aSRichard Henderson 
952*d8e59c4aSRichard Henderson         tcg_temp_free_i32(t1);
953*d8e59c4aSRichard Henderson         tcg_temp_free_i32(treg);
954*d8e59c4aSRichard Henderson         tcg_temp_free_i32(tsize);
955*d8e59c4aSRichard Henderson     }
956*d8e59c4aSRichard Henderson 
957*d8e59c4aSRichard Henderson     tcg_temp_free(addr);
958*d8e59c4aSRichard Henderson     return true;
959*d8e59c4aSRichard Henderson }
960*d8e59c4aSRichard Henderson 
961*d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
962*d8e59c4aSRichard Henderson {
963*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
964*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
965*d8e59c4aSRichard Henderson }
966*d8e59c4aSRichard Henderson 
967*d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
968*d8e59c4aSRichard Henderson {
969*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
970*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
971*d8e59c4aSRichard Henderson }
972*d8e59c4aSRichard Henderson 
973*d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
974*d8e59c4aSRichard Henderson {
975*d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
976*d8e59c4aSRichard Henderson         return true;
977*d8e59c4aSRichard Henderson     }
978*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
979*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
980*d8e59c4aSRichard Henderson }
981*d8e59c4aSRichard Henderson 
982*d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
983*d8e59c4aSRichard Henderson {
984*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
985*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
986*d8e59c4aSRichard Henderson }
987*d8e59c4aSRichard Henderson 
988*d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
989*d8e59c4aSRichard Henderson {
990*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
991*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
992*d8e59c4aSRichard Henderson }
993*d8e59c4aSRichard Henderson 
994*d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
995*d8e59c4aSRichard Henderson {
996*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
997*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
998*d8e59c4aSRichard Henderson }
999*d8e59c4aSRichard Henderson 
1000*d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
1001*d8e59c4aSRichard Henderson {
1002*d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
1003*d8e59c4aSRichard Henderson         return true;
1004*d8e59c4aSRichard Henderson     }
1005*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1006*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
1007*d8e59c4aSRichard Henderson }
1008*d8e59c4aSRichard Henderson 
1009*d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
1010*d8e59c4aSRichard Henderson {
1011*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1012*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
1013*d8e59c4aSRichard Henderson }
1014*d8e59c4aSRichard Henderson 
1015*d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
1016*d8e59c4aSRichard Henderson {
1017*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1018*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1019*d8e59c4aSRichard Henderson }
1020*d8e59c4aSRichard Henderson 
1021*d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
1022*d8e59c4aSRichard Henderson {
1023*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1024*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
1025*d8e59c4aSRichard Henderson }
1026*d8e59c4aSRichard Henderson 
1027*d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
1028*d8e59c4aSRichard Henderson {
1029*d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
1030*d8e59c4aSRichard Henderson         return true;
1031*d8e59c4aSRichard Henderson     }
1032*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1033*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
1034*d8e59c4aSRichard Henderson }
1035*d8e59c4aSRichard Henderson 
1036*d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1037*d8e59c4aSRichard Henderson {
1038*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1039*d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1040*d8e59c4aSRichard Henderson }
1041*d8e59c4aSRichard Henderson 
1042*d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1043*d8e59c4aSRichard Henderson {
1044*d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1045*d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1046*d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1047*d8e59c4aSRichard Henderson     TCGv_i32 tval;
1048*d8e59c4aSRichard Henderson 
1049*d8e59c4aSRichard Henderson     t_sync_flags(dc);
1050*d8e59c4aSRichard Henderson     sync_jmpstate(dc);
1051*d8e59c4aSRichard Henderson 
1052*d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1053*d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1054*d8e59c4aSRichard Henderson 
1055*d8e59c4aSRichard Henderson     /*
1056*d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1057*d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1058*d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1059*d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1060*d8e59c4aSRichard Henderson      */
1061*d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1062*d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1063*d8e59c4aSRichard Henderson 
1064*d8e59c4aSRichard Henderson     /*
1065*d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1066*d8e59c4aSRichard Henderson      * the reserved location.
1067*d8e59c4aSRichard Henderson      */
1068*d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1069*d8e59c4aSRichard Henderson 
1070*d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1071*d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1072*d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1073*d8e59c4aSRichard Henderson 
1074*d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1075*d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1076*d8e59c4aSRichard Henderson 
1077*d8e59c4aSRichard Henderson     /* Success */
1078*d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1079*d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1080*d8e59c4aSRichard Henderson 
1081*d8e59c4aSRichard Henderson     /* Failure */
1082*d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1083*d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1084*d8e59c4aSRichard Henderson 
1085*d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1086*d8e59c4aSRichard Henderson 
1087*d8e59c4aSRichard Henderson     /*
1088*d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1089*d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1090*d8e59c4aSRichard Henderson      */
1091*d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1092*d8e59c4aSRichard Henderson     return true;
1093*d8e59c4aSRichard Henderson }
1094*d8e59c4aSRichard Henderson 
109520800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
109620800179SRichard Henderson {
109720800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
109820800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
109920800179SRichard Henderson         trap_illegal(dc, true);
110020800179SRichard Henderson         return true;
110120800179SRichard Henderson     }
110220800179SRichard Henderson     /*
110320800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
110420800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
110520800179SRichard Henderson      */
110620800179SRichard Henderson     return false;
1107fcf5ef2aSThomas Huth }
1108fcf5ef2aSThomas Huth 
11091074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1110fcf5ef2aSThomas Huth {
11111074c0fbSRichard Henderson     TCGv_i32 t;
11121074c0fbSRichard Henderson 
11131074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
11141074c0fbSRichard Henderson     t = tcg_temp_new_i32();
11151074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
11161074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
11171074c0fbSRichard Henderson     tcg_temp_free_i32(t);
1118fcf5ef2aSThomas Huth }
1119fcf5ef2aSThomas Huth 
11201074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v)
1121fcf5ef2aSThomas Huth {
1122fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
11231074c0fbSRichard Henderson 
11241074c0fbSRichard Henderson     /* Install MSR_C.  */
11251074c0fbSRichard Henderson     tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
11261074c0fbSRichard Henderson 
11271074c0fbSRichard Henderson     /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
11281074c0fbSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
1129fcf5ef2aSThomas Huth }
1130fcf5ef2aSThomas Huth 
1131fcf5ef2aSThomas Huth static void dec_msr(DisasContext *dc)
1132fcf5ef2aSThomas Huth {
1133fcf5ef2aSThomas Huth     CPUState *cs = CPU(dc->cpu);
1134cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
11352023e9a3SEdgar E. Iglesias     unsigned int sr, rn;
1136f0f7e7f7SEdgar E. Iglesias     bool to, clrset, extended = false;
1137fcf5ef2aSThomas Huth 
11382023e9a3SEdgar E. Iglesias     sr = extract32(dc->imm, 0, 14);
11392023e9a3SEdgar E. Iglesias     to = extract32(dc->imm, 14, 1);
11402023e9a3SEdgar E. Iglesias     clrset = extract32(dc->imm, 15, 1) == 0;
1141fcf5ef2aSThomas Huth     dc->type_b = 1;
11422023e9a3SEdgar E. Iglesias     if (to) {
1143fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1144f0f7e7f7SEdgar E. Iglesias     }
1145f0f7e7f7SEdgar E. Iglesias 
1146f0f7e7f7SEdgar E. Iglesias     /* Extended MSRs are only available if addr_size > 32.  */
1147f0f7e7f7SEdgar E. Iglesias     if (dc->cpu->cfg.addr_size > 32) {
1148f0f7e7f7SEdgar E. Iglesias         /* The E-bit is encoded differently for To/From MSR.  */
1149f0f7e7f7SEdgar E. Iglesias         static const unsigned int e_bit[] = { 19, 24 };
1150f0f7e7f7SEdgar E. Iglesias 
1151f0f7e7f7SEdgar E. Iglesias         extended = extract32(dc->imm, e_bit[to], 1);
11522023e9a3SEdgar E. Iglesias     }
1153fcf5ef2aSThomas Huth 
1154fcf5ef2aSThomas Huth     /* msrclr and msrset.  */
11552023e9a3SEdgar E. Iglesias     if (clrset) {
11562023e9a3SEdgar E. Iglesias         bool clr = extract32(dc->ir, 16, 1);
1157fcf5ef2aSThomas Huth 
115856837509SEdgar E. Iglesias         if (!dc->cpu->cfg.use_msr_instr) {
1159fcf5ef2aSThomas Huth             /* nop??? */
1160fcf5ef2aSThomas Huth             return;
1161fcf5ef2aSThomas Huth         }
1162fcf5ef2aSThomas Huth 
1163bdfc1e88SEdgar E. Iglesias         if (trap_userspace(dc, dc->imm != 4 && dc->imm != 0)) {
1164fcf5ef2aSThomas Huth             return;
1165fcf5ef2aSThomas Huth         }
1166fcf5ef2aSThomas Huth 
1167fcf5ef2aSThomas Huth         if (dc->rd)
1168fcf5ef2aSThomas Huth             msr_read(dc, cpu_R[dc->rd]);
1169fcf5ef2aSThomas Huth 
1170cfeea807SEdgar E. Iglesias         t0 = tcg_temp_new_i32();
1171cfeea807SEdgar E. Iglesias         t1 = tcg_temp_new_i32();
1172fcf5ef2aSThomas Huth         msr_read(dc, t0);
1173cfeea807SEdgar E. Iglesias         tcg_gen_mov_i32(t1, *(dec_alu_op_b(dc)));
1174fcf5ef2aSThomas Huth 
1175fcf5ef2aSThomas Huth         if (clr) {
1176cfeea807SEdgar E. Iglesias             tcg_gen_not_i32(t1, t1);
1177cfeea807SEdgar E. Iglesias             tcg_gen_and_i32(t0, t0, t1);
1178fcf5ef2aSThomas Huth         } else
1179cfeea807SEdgar E. Iglesias             tcg_gen_or_i32(t0, t0, t1);
1180fcf5ef2aSThomas Huth         msr_write(dc, t0);
1181cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t0);
1182cfeea807SEdgar E. Iglesias         tcg_temp_free_i32(t1);
1183d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1184d4705ae0SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1185fcf5ef2aSThomas Huth         return;
1186fcf5ef2aSThomas Huth     }
1187fcf5ef2aSThomas Huth 
1188bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, to)) {
1189fcf5ef2aSThomas Huth         return;
1190fcf5ef2aSThomas Huth     }
1191fcf5ef2aSThomas Huth 
1192fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
1193fcf5ef2aSThomas Huth     /* Catch read/writes to the mmu block.  */
1194fcf5ef2aSThomas Huth     if ((sr & ~0xff) == 0x1000) {
1195f0f7e7f7SEdgar E. Iglesias         TCGv_i32 tmp_ext = tcg_const_i32(extended);
119605a9a651SEdgar E. Iglesias         TCGv_i32 tmp_sr;
119705a9a651SEdgar E. Iglesias 
1198fcf5ef2aSThomas Huth         sr &= 7;
119905a9a651SEdgar E. Iglesias         tmp_sr = tcg_const_i32(sr);
120005a9a651SEdgar E. Iglesias         if (to) {
1201f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_sr, cpu_R[dc->ra]);
120205a9a651SEdgar E. Iglesias         } else {
1203f0f7e7f7SEdgar E. Iglesias             gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tmp_ext, tmp_sr);
120405a9a651SEdgar E. Iglesias         }
120505a9a651SEdgar E. Iglesias         tcg_temp_free_i32(tmp_sr);
1206f0f7e7f7SEdgar E. Iglesias         tcg_temp_free_i32(tmp_ext);
1207fcf5ef2aSThomas Huth         return;
1208fcf5ef2aSThomas Huth     }
1209fcf5ef2aSThomas Huth #endif
1210fcf5ef2aSThomas Huth 
1211fcf5ef2aSThomas Huth     if (to) {
1212fcf5ef2aSThomas Huth         switch (sr) {
1213aa28e6d4SRichard Henderson             case SR_PC:
1214fcf5ef2aSThomas Huth                 break;
1215aa28e6d4SRichard Henderson             case SR_MSR:
1216fcf5ef2aSThomas Huth                 msr_write(dc, cpu_R[dc->ra]);
1217fcf5ef2aSThomas Huth                 break;
1218351527b7SEdgar E. Iglesias             case SR_EAR:
1219dbdb77c4SRichard Henderson                 {
1220dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
1221dbdb77c4SRichard Henderson                     tcg_gen_extu_i32_i64(t64, cpu_R[dc->ra]);
1222dbdb77c4SRichard Henderson                     tcg_gen_st_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1223dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
1224dbdb77c4SRichard Henderson                 }
1225aa28e6d4SRichard Henderson                 break;
1226351527b7SEdgar E. Iglesias             case SR_ESR:
122741ba37c4SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
122841ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
1229aa28e6d4SRichard Henderson                 break;
1230ab6dd380SEdgar E. Iglesias             case SR_FSR:
123186017ccfSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
123286017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
1233aa28e6d4SRichard Henderson                 break;
1234aa28e6d4SRichard Henderson             case SR_BTR:
1235ccf628b7SRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
1236ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
1237aa28e6d4SRichard Henderson                 break;
1238aa28e6d4SRichard Henderson             case SR_EDR:
123939db007eSRichard Henderson                 tcg_gen_st_i32(cpu_R[dc->ra],
124039db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
1241fcf5ef2aSThomas Huth                 break;
1242fcf5ef2aSThomas Huth             case 0x800:
1243cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
1244cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
1245fcf5ef2aSThomas Huth                 break;
1246fcf5ef2aSThomas Huth             case 0x802:
1247cfeea807SEdgar E. Iglesias                 tcg_gen_st_i32(cpu_R[dc->ra],
1248cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
1249fcf5ef2aSThomas Huth                 break;
1250fcf5ef2aSThomas Huth             default:
1251fcf5ef2aSThomas Huth                 cpu_abort(CPU(dc->cpu), "unknown mts reg %x\n", sr);
1252fcf5ef2aSThomas Huth                 break;
1253fcf5ef2aSThomas Huth         }
1254fcf5ef2aSThomas Huth     } else {
1255fcf5ef2aSThomas Huth         switch (sr) {
1256aa28e6d4SRichard Henderson             case SR_PC:
1257d4705ae0SRichard Henderson                 tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1258fcf5ef2aSThomas Huth                 break;
1259aa28e6d4SRichard Henderson             case SR_MSR:
1260fcf5ef2aSThomas Huth                 msr_read(dc, cpu_R[dc->rd]);
1261fcf5ef2aSThomas Huth                 break;
1262351527b7SEdgar E. Iglesias             case SR_EAR:
1263dbdb77c4SRichard Henderson                 {
1264dbdb77c4SRichard Henderson                     TCGv_i64 t64 = tcg_temp_new_i64();
1265dbdb77c4SRichard Henderson                     tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1266a1b48e3aSEdgar E. Iglesias                     if (extended) {
1267dbdb77c4SRichard Henderson                         tcg_gen_extrh_i64_i32(cpu_R[dc->rd], t64);
1268aa28e6d4SRichard Henderson                     } else {
1269dbdb77c4SRichard Henderson                         tcg_gen_extrl_i64_i32(cpu_R[dc->rd], t64);
1270dbdb77c4SRichard Henderson                     }
1271dbdb77c4SRichard Henderson                     tcg_temp_free_i64(t64);
1272a1b48e3aSEdgar E. Iglesias                 }
1273aa28e6d4SRichard Henderson                 break;
1274351527b7SEdgar E. Iglesias             case SR_ESR:
127541ba37c4SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
127641ba37c4SRichard Henderson                                cpu_env, offsetof(CPUMBState, esr));
1277aa28e6d4SRichard Henderson                 break;
1278351527b7SEdgar E. Iglesias             case SR_FSR:
127986017ccfSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
128086017ccfSRichard Henderson                                cpu_env, offsetof(CPUMBState, fsr));
1281aa28e6d4SRichard Henderson                 break;
1282351527b7SEdgar E. Iglesias             case SR_BTR:
1283ccf628b7SRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
1284ccf628b7SRichard Henderson                                cpu_env, offsetof(CPUMBState, btr));
1285aa28e6d4SRichard Henderson                 break;
12867cdae31dSTong Ho             case SR_EDR:
128739db007eSRichard Henderson                 tcg_gen_ld_i32(cpu_R[dc->rd],
128839db007eSRichard Henderson                                cpu_env, offsetof(CPUMBState, edr));
1289fcf5ef2aSThomas Huth                 break;
1290fcf5ef2aSThomas Huth             case 0x800:
1291cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1292cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, slr));
1293fcf5ef2aSThomas Huth                 break;
1294fcf5ef2aSThomas Huth             case 0x802:
1295cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1296cfeea807SEdgar E. Iglesias                                cpu_env, offsetof(CPUMBState, shr));
1297fcf5ef2aSThomas Huth                 break;
1298351527b7SEdgar E. Iglesias             case 0x2000 ... 0x200c:
1299fcf5ef2aSThomas Huth                 rn = sr & 0xf;
1300cfeea807SEdgar E. Iglesias                 tcg_gen_ld_i32(cpu_R[dc->rd],
1301fcf5ef2aSThomas Huth                               cpu_env, offsetof(CPUMBState, pvr.regs[rn]));
1302fcf5ef2aSThomas Huth                 break;
1303fcf5ef2aSThomas Huth             default:
1304fcf5ef2aSThomas Huth                 cpu_abort(cs, "unknown mfs reg %x\n", sr);
1305fcf5ef2aSThomas Huth                 break;
1306fcf5ef2aSThomas Huth         }
1307fcf5ef2aSThomas Huth     }
1308fcf5ef2aSThomas Huth 
1309fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1310cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(cpu_R[0], 0);
1311fcf5ef2aSThomas Huth     }
1312fcf5ef2aSThomas Huth }
1313fcf5ef2aSThomas Huth 
1314fcf5ef2aSThomas Huth static inline void eval_cc(DisasContext *dc, unsigned int cc,
13159e6e1828SEdgar E. Iglesias                            TCGv_i32 d, TCGv_i32 a)
1316fcf5ef2aSThomas Huth {
1317d89b86e9SEdgar E. Iglesias     static const int mb_to_tcg_cc[] = {
1318d89b86e9SEdgar E. Iglesias         [CC_EQ] = TCG_COND_EQ,
1319d89b86e9SEdgar E. Iglesias         [CC_NE] = TCG_COND_NE,
1320d89b86e9SEdgar E. Iglesias         [CC_LT] = TCG_COND_LT,
1321d89b86e9SEdgar E. Iglesias         [CC_LE] = TCG_COND_LE,
1322d89b86e9SEdgar E. Iglesias         [CC_GE] = TCG_COND_GE,
1323d89b86e9SEdgar E. Iglesias         [CC_GT] = TCG_COND_GT,
1324d89b86e9SEdgar E. Iglesias     };
1325d89b86e9SEdgar E. Iglesias 
1326fcf5ef2aSThomas Huth     switch (cc) {
1327fcf5ef2aSThomas Huth     case CC_EQ:
1328fcf5ef2aSThomas Huth     case CC_NE:
1329fcf5ef2aSThomas Huth     case CC_LT:
1330fcf5ef2aSThomas Huth     case CC_LE:
1331fcf5ef2aSThomas Huth     case CC_GE:
1332fcf5ef2aSThomas Huth     case CC_GT:
13339e6e1828SEdgar E. Iglesias         tcg_gen_setcondi_i32(mb_to_tcg_cc[cc], d, a, 0);
1334fcf5ef2aSThomas Huth         break;
1335fcf5ef2aSThomas Huth     default:
1336fcf5ef2aSThomas Huth         cpu_abort(CPU(dc->cpu), "Unknown condition code %x.\n", cc);
1337fcf5ef2aSThomas Huth         break;
1338fcf5ef2aSThomas Huth     }
1339fcf5ef2aSThomas Huth }
1340fcf5ef2aSThomas Huth 
13410f96e96bSRichard Henderson static void eval_cond_jmp(DisasContext *dc, TCGv_i32 pc_true, TCGv_i32 pc_false)
1342fcf5ef2aSThomas Huth {
13430f96e96bSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
1344e956caf2SEdgar E. Iglesias 
13450f96e96bSRichard Henderson     tcg_gen_movcond_i32(TCG_COND_NE, cpu_pc,
13469b158558SRichard Henderson                         cpu_btaken, zero,
1347e956caf2SEdgar E. Iglesias                         pc_true, pc_false);
1348e956caf2SEdgar E. Iglesias 
13490f96e96bSRichard Henderson     tcg_temp_free_i32(zero);
1350fcf5ef2aSThomas Huth }
1351fcf5ef2aSThomas Huth 
1352f91c60f0SEdgar E. Iglesias static void dec_setup_dslot(DisasContext *dc)
1353f91c60f0SEdgar E. Iglesias {
1354f91c60f0SEdgar E. Iglesias         TCGv_i32 tmp = tcg_const_i32(dc->type_b && (dc->tb_flags & IMM_FLAG));
1355f91c60f0SEdgar E. Iglesias 
1356f91c60f0SEdgar E. Iglesias         dc->delayed_branch = 2;
1357f91c60f0SEdgar E. Iglesias         dc->tb_flags |= D_FLAG;
1358f91c60f0SEdgar E. Iglesias 
1359f91c60f0SEdgar E. Iglesias         tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, bimm));
1360f91c60f0SEdgar E. Iglesias         tcg_temp_free_i32(tmp);
1361f91c60f0SEdgar E. Iglesias }
1362f91c60f0SEdgar E. Iglesias 
1363fcf5ef2aSThomas Huth static void dec_bcc(DisasContext *dc)
1364fcf5ef2aSThomas Huth {
1365fcf5ef2aSThomas Huth     unsigned int cc;
1366fcf5ef2aSThomas Huth     unsigned int dslot;
1367fcf5ef2aSThomas Huth 
1368fcf5ef2aSThomas Huth     cc = EXTRACT_FIELD(dc->ir, 21, 23);
1369fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 25);
1370fcf5ef2aSThomas Huth 
1371fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1372fcf5ef2aSThomas Huth     if (dslot) {
1373f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1374fcf5ef2aSThomas Huth     }
1375fcf5ef2aSThomas Huth 
1376d7ecb757SRichard Henderson     if (dc->type_b) {
1377fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT_CC;
1378d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1379d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1380fcf5ef2aSThomas Huth     } else {
1381fcf5ef2aSThomas Huth         dc->jmp = JMP_INDIRECT;
1382d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1383fcf5ef2aSThomas Huth     }
13849b158558SRichard Henderson     eval_cc(dc, cc, cpu_btaken, cpu_R[dc->ra]);
1385fcf5ef2aSThomas Huth }
1386fcf5ef2aSThomas Huth 
1387fcf5ef2aSThomas Huth static void dec_br(DisasContext *dc)
1388fcf5ef2aSThomas Huth {
1389fcf5ef2aSThomas Huth     unsigned int dslot, link, abs, mbar;
1390fcf5ef2aSThomas Huth 
1391fcf5ef2aSThomas Huth     dslot = dc->ir & (1 << 20);
1392fcf5ef2aSThomas Huth     abs = dc->ir & (1 << 19);
1393fcf5ef2aSThomas Huth     link = dc->ir & (1 << 18);
1394fcf5ef2aSThomas Huth 
1395fcf5ef2aSThomas Huth     /* Memory barrier.  */
1396fcf5ef2aSThomas Huth     mbar = (dc->ir >> 16) & 31;
1397fcf5ef2aSThomas Huth     if (mbar == 2 && dc->imm == 4) {
1398badcbf9dSEdgar E. Iglesias         uint16_t mbar_imm = dc->rd;
1399badcbf9dSEdgar E. Iglesias 
14003f172744SEdgar E. Iglesias         /* Data access memory barrier.  */
14013f172744SEdgar E. Iglesias         if ((mbar_imm & 2) == 0) {
14023f172744SEdgar E. Iglesias             tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
14033f172744SEdgar E. Iglesias         }
14043f172744SEdgar E. Iglesias 
1405fcf5ef2aSThomas Huth         /* mbar IMM & 16 decodes to sleep.  */
1406badcbf9dSEdgar E. Iglesias         if (mbar_imm & 16) {
140741ba37c4SRichard Henderson             TCGv_i32 tmp_1;
1408fcf5ef2aSThomas Huth 
1409b4919e7dSEdgar E. Iglesias             if (trap_userspace(dc, true)) {
1410b4919e7dSEdgar E. Iglesias                 /* Sleep is a privileged instruction.  */
1411b4919e7dSEdgar E. Iglesias                 return;
1412b4919e7dSEdgar E. Iglesias             }
1413b4919e7dSEdgar E. Iglesias 
1414fcf5ef2aSThomas Huth             t_sync_flags(dc);
141541ba37c4SRichard Henderson 
141641ba37c4SRichard Henderson             tmp_1 = tcg_const_i32(1);
1417fcf5ef2aSThomas Huth             tcg_gen_st_i32(tmp_1, cpu_env,
1418fcf5ef2aSThomas Huth                            -offsetof(MicroBlazeCPU, env)
1419fcf5ef2aSThomas Huth                            +offsetof(CPUState, halted));
1420fcf5ef2aSThomas Huth             tcg_temp_free_i32(tmp_1);
142141ba37c4SRichard Henderson 
1422d4705ae0SRichard Henderson             tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
142341ba37c4SRichard Henderson 
142441ba37c4SRichard Henderson             gen_raise_exception(dc, EXCP_HLT);
1425fcf5ef2aSThomas Huth             return;
1426fcf5ef2aSThomas Huth         }
1427fcf5ef2aSThomas Huth         /* Break the TB.  */
1428fcf5ef2aSThomas Huth         dc->cpustate_changed = 1;
1429fcf5ef2aSThomas Huth         return;
1430fcf5ef2aSThomas Huth     }
1431fcf5ef2aSThomas Huth 
1432d7ecb757SRichard Henderson     if (abs && link && !dslot) {
1433d7ecb757SRichard Henderson         if (dc->type_b) {
1434d7ecb757SRichard Henderson             /* BRKI */
1435d7ecb757SRichard Henderson             uint32_t imm = dec_alu_typeb_imm(dc);
1436d7ecb757SRichard Henderson             if (trap_userspace(dc, imm != 8 && imm != 0x18)) {
1437d7ecb757SRichard Henderson                 return;
1438d7ecb757SRichard Henderson             }
1439d7ecb757SRichard Henderson         } else {
1440d7ecb757SRichard Henderson             /* BRK */
1441d7ecb757SRichard Henderson             if (trap_userspace(dc, true)) {
1442d7ecb757SRichard Henderson                 return;
1443d7ecb757SRichard Henderson             }
1444d7ecb757SRichard Henderson         }
1445d7ecb757SRichard Henderson     }
1446d7ecb757SRichard Henderson 
1447fcf5ef2aSThomas Huth     dc->delayed_branch = 1;
1448fcf5ef2aSThomas Huth     if (dslot) {
1449f91c60f0SEdgar E. Iglesias         dec_setup_dslot(dc);
1450fcf5ef2aSThomas Huth     }
1451d7ecb757SRichard Henderson     if (link && dc->rd) {
1452d4705ae0SRichard Henderson         tcg_gen_movi_i32(cpu_R[dc->rd], dc->base.pc_next);
1453d7ecb757SRichard Henderson     }
1454fcf5ef2aSThomas Huth 
1455fcf5ef2aSThomas Huth     if (abs) {
1456d7ecb757SRichard Henderson         if (dc->type_b) {
1457d7ecb757SRichard Henderson             uint32_t dest = dec_alu_typeb_imm(dc);
1458d7ecb757SRichard Henderson 
1459d7ecb757SRichard Henderson             dc->jmp = JMP_DIRECT;
1460d7ecb757SRichard Henderson             dc->jmp_pc = dest;
1461d7ecb757SRichard Henderson             tcg_gen_movi_i32(cpu_btarget, dest);
1462fcf5ef2aSThomas Huth             if (link && !dslot) {
1463d7ecb757SRichard Henderson                 switch (dest) {
1464d7ecb757SRichard Henderson                 case 8:
1465d7ecb757SRichard Henderson                 case 0x18:
1466d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_BREAK);
1467d7ecb757SRichard Henderson                     break;
1468d7ecb757SRichard Henderson                 case 0:
1469d7ecb757SRichard Henderson                     gen_raise_exception_sync(dc, EXCP_DEBUG);
1470d7ecb757SRichard Henderson                     break;
1471d7ecb757SRichard Henderson                 }
1472d7ecb757SRichard Henderson             }
1473d7ecb757SRichard Henderson         } else {
1474d7ecb757SRichard Henderson             dc->jmp = JMP_INDIRECT;
1475d7ecb757SRichard Henderson             tcg_gen_mov_i32(cpu_btarget, cpu_R[dc->rb]);
1476d7ecb757SRichard Henderson             if (link && !dslot) {
147741ba37c4SRichard Henderson                 gen_raise_exception_sync(dc, EXCP_BREAK);
147841ba37c4SRichard Henderson             }
1479fcf5ef2aSThomas Huth         }
1480d7ecb757SRichard Henderson     } else if (dc->type_b) {
1481fcf5ef2aSThomas Huth         dc->jmp = JMP_DIRECT;
1482d7ecb757SRichard Henderson         dc->jmp_pc = dc->base.pc_next + dec_alu_typeb_imm(dc);
1483d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_pc);
1484fcf5ef2aSThomas Huth     } else {
1485d7ecb757SRichard Henderson         dc->jmp = JMP_INDIRECT;
1486d7ecb757SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dc->rb], dc->base.pc_next);
1487d7ecb757SRichard Henderson     }
14889b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
1489fcf5ef2aSThomas Huth }
1490fcf5ef2aSThomas Huth 
1491fcf5ef2aSThomas Huth static inline void do_rti(DisasContext *dc)
1492fcf5ef2aSThomas Huth {
1493cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1494cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1495cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
14963e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
14970a22f8cfSEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
14980a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_IE);
1499cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1500fcf5ef2aSThomas Huth 
1501cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1502cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1503fcf5ef2aSThomas Huth     msr_write(dc, t1);
1504cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1505cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1506fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1507fcf5ef2aSThomas Huth }
1508fcf5ef2aSThomas Huth 
1509fcf5ef2aSThomas Huth static inline void do_rtb(DisasContext *dc)
1510fcf5ef2aSThomas Huth {
1511cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1512cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1513cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
15143e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
15150a22f8cfSEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_BIP);
1516cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1517cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1518fcf5ef2aSThomas Huth 
1519cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1520cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1521fcf5ef2aSThomas Huth     msr_write(dc, t1);
1522cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1523cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1524fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1525fcf5ef2aSThomas Huth }
1526fcf5ef2aSThomas Huth 
1527fcf5ef2aSThomas Huth static inline void do_rte(DisasContext *dc)
1528fcf5ef2aSThomas Huth {
1529cfeea807SEdgar E. Iglesias     TCGv_i32 t0, t1;
1530cfeea807SEdgar E. Iglesias     t0 = tcg_temp_new_i32();
1531cfeea807SEdgar E. Iglesias     t1 = tcg_temp_new_i32();
1532fcf5ef2aSThomas Huth 
15333e0e16aeSRichard Henderson     tcg_gen_mov_i32(t1, cpu_msr);
15340a22f8cfSEdgar E. Iglesias     tcg_gen_ori_i32(t1, t1, MSR_EE);
1535cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~MSR_EIP);
1536cfeea807SEdgar E. Iglesias     tcg_gen_shri_i32(t0, t1, 1);
1537cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t0, t0, (MSR_VM | MSR_UM));
1538fcf5ef2aSThomas Huth 
1539cfeea807SEdgar E. Iglesias     tcg_gen_andi_i32(t1, t1, ~(MSR_VM | MSR_UM));
1540cfeea807SEdgar E. Iglesias     tcg_gen_or_i32(t1, t1, t0);
1541fcf5ef2aSThomas Huth     msr_write(dc, t1);
1542cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t1);
1543cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t0);
1544fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1545fcf5ef2aSThomas Huth }
1546fcf5ef2aSThomas Huth 
1547fcf5ef2aSThomas Huth static void dec_rts(DisasContext *dc)
1548fcf5ef2aSThomas Huth {
1549fcf5ef2aSThomas Huth     unsigned int b_bit, i_bit, e_bit;
1550fcf5ef2aSThomas Huth 
1551fcf5ef2aSThomas Huth     i_bit = dc->ir & (1 << 21);
1552fcf5ef2aSThomas Huth     b_bit = dc->ir & (1 << 22);
1553fcf5ef2aSThomas Huth     e_bit = dc->ir & (1 << 23);
1554fcf5ef2aSThomas Huth 
1555bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, i_bit || b_bit || e_bit)) {
1556bdfc1e88SEdgar E. Iglesias         return;
1557bdfc1e88SEdgar E. Iglesias     }
1558bdfc1e88SEdgar E. Iglesias 
1559f91c60f0SEdgar E. Iglesias     dec_setup_dslot(dc);
1560fcf5ef2aSThomas Huth 
1561fcf5ef2aSThomas Huth     if (i_bit) {
1562fcf5ef2aSThomas Huth         dc->tb_flags |= DRTI_FLAG;
1563fcf5ef2aSThomas Huth     } else if (b_bit) {
1564fcf5ef2aSThomas Huth         dc->tb_flags |= DRTB_FLAG;
1565fcf5ef2aSThomas Huth     } else if (e_bit) {
1566fcf5ef2aSThomas Huth         dc->tb_flags |= DRTE_FLAG;
156711105d67SRichard Henderson     }
1568fcf5ef2aSThomas Huth 
1569fcf5ef2aSThomas Huth     dc->jmp = JMP_INDIRECT;
15709b158558SRichard Henderson     tcg_gen_movi_i32(cpu_btaken, 1);
15710f96e96bSRichard Henderson     tcg_gen_add_i32(cpu_btarget, cpu_R[dc->ra], *dec_alu_op_b(dc));
1572fcf5ef2aSThomas Huth }
1573fcf5ef2aSThomas Huth 
1574fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc)
1575fcf5ef2aSThomas Huth {
15769ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, true)) {
1577fcf5ef2aSThomas Huth         return;
1578fcf5ef2aSThomas Huth     }
1579d4705ae0SRichard Henderson     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n",
1580d4705ae0SRichard Henderson                   (uint32_t)dc->base.pc_next, dc->opcode);
1581fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 1;
1582fcf5ef2aSThomas Huth }
1583fcf5ef2aSThomas Huth 
1584fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
1585fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc)
1586fcf5ef2aSThomas Huth {
1587fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1588fcf5ef2aSThomas Huth     int ctrl;
1589fcf5ef2aSThomas Huth 
1590bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
1591fcf5ef2aSThomas Huth         return;
1592fcf5ef2aSThomas Huth     }
1593fcf5ef2aSThomas Huth 
1594cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
1595fcf5ef2aSThomas Huth     if (dc->type_b) {
1596cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(t_id, dc->imm & 0xf);
1597fcf5ef2aSThomas Huth         ctrl = dc->imm >> 10;
1598fcf5ef2aSThomas Huth     } else {
1599cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
1600fcf5ef2aSThomas Huth         ctrl = dc->imm >> 5;
1601fcf5ef2aSThomas Huth     }
1602fcf5ef2aSThomas Huth 
1603cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
1604fcf5ef2aSThomas Huth 
1605fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1606fcf5ef2aSThomas Huth         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1607fcf5ef2aSThomas Huth     } else {
1608fcf5ef2aSThomas Huth         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1609fcf5ef2aSThomas Huth     }
1610cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1611cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
1612fcf5ef2aSThomas Huth }
1613fcf5ef2aSThomas Huth 
1614fcf5ef2aSThomas Huth static struct decoder_info {
1615fcf5ef2aSThomas Huth     struct {
1616fcf5ef2aSThomas Huth         uint32_t bits;
1617fcf5ef2aSThomas Huth         uint32_t mask;
1618fcf5ef2aSThomas Huth     };
1619fcf5ef2aSThomas Huth     void (*dec)(DisasContext *dc);
1620fcf5ef2aSThomas Huth } decinfo[] = {
1621fcf5ef2aSThomas Huth     {DEC_BR, dec_br},
1622fcf5ef2aSThomas Huth     {DEC_BCC, dec_bcc},
1623fcf5ef2aSThomas Huth     {DEC_RTS, dec_rts},
1624fcf5ef2aSThomas Huth     {DEC_MSR, dec_msr},
1625fcf5ef2aSThomas Huth     {DEC_STREAM, dec_stream},
1626fcf5ef2aSThomas Huth     {{0, 0}, dec_null}
1627fcf5ef2aSThomas Huth };
1628fcf5ef2aSThomas Huth 
162944d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir)
1630fcf5ef2aSThomas Huth {
1631fcf5ef2aSThomas Huth     int i;
1632fcf5ef2aSThomas Huth 
1633fcf5ef2aSThomas Huth     dc->ir = ir;
1634fcf5ef2aSThomas Huth 
1635fcf5ef2aSThomas Huth     /* bit 2 seems to indicate insn type.  */
1636fcf5ef2aSThomas Huth     dc->type_b = ir & (1 << 29);
1637fcf5ef2aSThomas Huth 
1638fcf5ef2aSThomas Huth     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1639fcf5ef2aSThomas Huth     dc->rd = EXTRACT_FIELD(ir, 21, 25);
1640fcf5ef2aSThomas Huth     dc->ra = EXTRACT_FIELD(ir, 16, 20);
1641fcf5ef2aSThomas Huth     dc->rb = EXTRACT_FIELD(ir, 11, 15);
1642fcf5ef2aSThomas Huth     dc->imm = EXTRACT_FIELD(ir, 0, 15);
1643fcf5ef2aSThomas Huth 
1644fcf5ef2aSThomas Huth     /* Large switch for all insns.  */
1645fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1646fcf5ef2aSThomas Huth         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1647fcf5ef2aSThomas Huth             decinfo[i].dec(dc);
1648fcf5ef2aSThomas Huth             break;
1649fcf5ef2aSThomas Huth         }
1650fcf5ef2aSThomas Huth     }
1651fcf5ef2aSThomas Huth }
1652fcf5ef2aSThomas Huth 
1653372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1654fcf5ef2aSThomas Huth {
1655372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1656372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1657372122e3SRichard Henderson     int bound;
1658fcf5ef2aSThomas Huth 
1659fcf5ef2aSThomas Huth     dc->cpu = cpu;
1660372122e3SRichard Henderson     dc->synced_flags = dc->tb_flags = dc->base.tb->flags;
1661fcf5ef2aSThomas Huth     dc->delayed_branch = !!(dc->tb_flags & D_FLAG);
1662372122e3SRichard Henderson     dc->jmp = dc->delayed_branch ? 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 {
1680372122e3SRichard Henderson     tcg_gen_insn_start(dcb->pc_next);
1681372122e3SRichard Henderson }
1682fcf5ef2aSThomas Huth 
1683372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1684372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1685372122e3SRichard Henderson {
1686372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1687372122e3SRichard Henderson 
1688372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1689372122e3SRichard Henderson 
1690372122e3SRichard Henderson     /*
1691372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1692372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1693372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1694372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1695372122e3SRichard Henderson      */
1696372122e3SRichard Henderson     dc->base.pc_next += 4;
1697372122e3SRichard Henderson     return true;
1698372122e3SRichard Henderson }
1699372122e3SRichard Henderson 
1700372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1701372122e3SRichard Henderson {
1702372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1703372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
170444d1432bSRichard Henderson     uint32_t ir;
1705372122e3SRichard Henderson 
1706372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1707372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1708372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1709372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1710fcf5ef2aSThomas Huth     }
1711fcf5ef2aSThomas Huth 
1712fcf5ef2aSThomas Huth     dc->clear_imm = 1;
171344d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
171444d1432bSRichard Henderson     if (!decode(dc, ir)) {
171544d1432bSRichard Henderson         old_decode(dc, ir);
171644d1432bSRichard Henderson     }
171720800179SRichard Henderson 
171820800179SRichard Henderson     if (dc->r0) {
171920800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
172020800179SRichard Henderson         dc->r0 = NULL;
172120800179SRichard Henderson         dc->r0_set = false;
172220800179SRichard Henderson     }
172320800179SRichard Henderson 
1724d7ecb757SRichard Henderson     if (dc->clear_imm && (dc->tb_flags & IMM_FLAG)) {
1725fcf5ef2aSThomas Huth         dc->tb_flags &= ~IMM_FLAG;
1726d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1727372122e3SRichard Henderson     }
1728d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1729fcf5ef2aSThomas Huth 
1730372122e3SRichard Henderson     if (dc->delayed_branch && --dc->delayed_branch == 0) {
1731372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
1732fcf5ef2aSThomas Huth             do_rti(dc);
1733372122e3SRichard Henderson         }
1734372122e3SRichard Henderson         if (dc->tb_flags & DRTB_FLAG) {
1735fcf5ef2aSThomas Huth             do_rtb(dc);
1736372122e3SRichard Henderson         }
1737372122e3SRichard Henderson         if (dc->tb_flags & DRTE_FLAG) {
1738fcf5ef2aSThomas Huth             do_rte(dc);
1739372122e3SRichard Henderson         }
1740fcf5ef2aSThomas Huth         /* Clear the delay slot flag.  */
1741fcf5ef2aSThomas Huth         dc->tb_flags &= ~D_FLAG;
1742372122e3SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1743372122e3SRichard Henderson     }
1744372122e3SRichard Henderson 
1745372122e3SRichard Henderson     /* Force an exit if the per-tb cpu state has changed.  */
1746372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
1747372122e3SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1748372122e3SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1749372122e3SRichard Henderson     }
1750372122e3SRichard Henderson }
1751372122e3SRichard Henderson 
1752372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1753372122e3SRichard Henderson {
1754372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1755372122e3SRichard Henderson 
1756372122e3SRichard Henderson     assert(!dc->abort_at_next_insn);
1757372122e3SRichard Henderson 
1758372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1759372122e3SRichard Henderson         /* We have already exited the TB. */
1760372122e3SRichard Henderson         return;
1761372122e3SRichard Henderson     }
1762372122e3SRichard Henderson 
1763372122e3SRichard Henderson     t_sync_flags(dc);
1764372122e3SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1765372122e3SRichard Henderson         sync_jmpstate(dc);
1766372122e3SRichard Henderson         dc->jmp = JMP_NOJMP;
1767372122e3SRichard Henderson     }
1768372122e3SRichard Henderson 
1769372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1770372122e3SRichard Henderson     case DISAS_TOO_MANY:
1771372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1772372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1773372122e3SRichard Henderson         return;
1774372122e3SRichard Henderson 
1775372122e3SRichard Henderson     case DISAS_UPDATE:
1776372122e3SRichard Henderson         assert(dc->jmp == JMP_NOJMP);
1777372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1778372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1779372122e3SRichard Henderson         } else {
1780372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1781372122e3SRichard Henderson         }
1782372122e3SRichard Henderson         return;
1783372122e3SRichard Henderson 
1784372122e3SRichard Henderson     case DISAS_JUMP:
1785372122e3SRichard Henderson         switch (dc->jmp) {
1786372122e3SRichard Henderson         case JMP_INDIRECT:
1787372122e3SRichard Henderson             {
1788d4705ae0SRichard Henderson                 TCGv_i32 tmp_pc = tcg_const_i32(dc->base.pc_next);
17890f96e96bSRichard Henderson                 eval_cond_jmp(dc, cpu_btarget, tmp_pc);
17900f96e96bSRichard Henderson                 tcg_temp_free_i32(tmp_pc);
1791372122e3SRichard Henderson 
1792372122e3SRichard Henderson                 if (unlikely(cs->singlestep_enabled)) {
1793372122e3SRichard Henderson                     gen_raise_exception(dc, EXCP_DEBUG);
1794372122e3SRichard Henderson                 } else {
1795372122e3SRichard Henderson                     tcg_gen_exit_tb(NULL, 0);
1796372122e3SRichard Henderson                 }
1797372122e3SRichard Henderson             }
1798372122e3SRichard Henderson             return;
1799372122e3SRichard Henderson 
1800372122e3SRichard Henderson         case JMP_DIRECT_CC:
1801372122e3SRichard Henderson             {
1802fcf5ef2aSThomas Huth                 TCGLabel *l1 = gen_new_label();
18039b158558SRichard Henderson                 tcg_gen_brcondi_i32(TCG_COND_NE, cpu_btaken, 0, l1);
1804d4705ae0SRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1805fcf5ef2aSThomas Huth                 gen_set_label(l1);
1806372122e3SRichard Henderson             }
1807372122e3SRichard Henderson             /* fall through */
1808372122e3SRichard Henderson 
1809372122e3SRichard Henderson         case JMP_DIRECT:
1810fcf5ef2aSThomas Huth             gen_goto_tb(dc, 0, dc->jmp_pc);
1811372122e3SRichard Henderson             return;
1812fcf5ef2aSThomas Huth         }
1813372122e3SRichard Henderson         /* fall through */
1814fcf5ef2aSThomas Huth 
1815a2b80dbdSRichard Henderson     default:
1816a2b80dbdSRichard Henderson         g_assert_not_reached();
1817fcf5ef2aSThomas Huth     }
1818fcf5ef2aSThomas Huth }
1819fcf5ef2aSThomas Huth 
1820372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1821372122e3SRichard Henderson {
1822372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1823372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1824fcf5ef2aSThomas Huth }
1825372122e3SRichard Henderson 
1826372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1827372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1828372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1829372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1830372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1831372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1832372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1833372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1834372122e3SRichard Henderson };
1835372122e3SRichard Henderson 
1836372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1837372122e3SRichard Henderson {
1838372122e3SRichard Henderson     DisasContext dc;
1839372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1840fcf5ef2aSThomas Huth }
1841fcf5ef2aSThomas Huth 
184290c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1843fcf5ef2aSThomas Huth {
1844fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1845fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
1846fcf5ef2aSThomas Huth     int i;
1847fcf5ef2aSThomas Huth 
184890c84c56SMarkus Armbruster     if (!env) {
1849fcf5ef2aSThomas Huth         return;
185090c84c56SMarkus Armbruster     }
1851fcf5ef2aSThomas Huth 
18520f96e96bSRichard Henderson     qemu_fprintf(f, "IN: PC=%x %s\n",
185376e8187dSRichard Henderson                  env->pc, lookup_symbol(env->pc));
18546efd5599SRichard Henderson     qemu_fprintf(f, "rmsr=%x resr=%x rear=%" PRIx64 " "
1855eb2022b7SRichard Henderson                  "imm=%x iflags=%x fsr=%x rbtr=%x\n",
185678e9caf2SRichard Henderson                  env->msr, env->esr, env->ear,
1857eb2022b7SRichard Henderson                  env->imm, env->iflags, env->fsr, env->btr);
18580f96e96bSRichard Henderson     qemu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
1859fcf5ef2aSThomas Huth                  env->btaken, env->btarget,
18602e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18612e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18622e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18632e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18642ead1b18SJoe Komlodi     for (i = 0; i < 12; i++) {
18652ead1b18SJoe Komlodi         qemu_fprintf(f, "rpvr%2.2d=%8.8x ", i, env->pvr.regs[i]);
18662ead1b18SJoe Komlodi         if ((i + 1) % 4 == 0) {
18672ead1b18SJoe Komlodi             qemu_fprintf(f, "\n");
18682ead1b18SJoe Komlodi         }
18692ead1b18SJoe Komlodi     }
1870fcf5ef2aSThomas Huth 
18712ead1b18SJoe Komlodi     /* Registers that aren't modeled are reported as 0 */
187239db007eSRichard Henderson     qemu_fprintf(f, "redr=%x rpid=0 rzpr=0 rtlbx=0 rtlbsx=0 "
1873af20a93aSRichard Henderson                     "rtlblo=0 rtlbhi=0\n", env->edr);
18742ead1b18SJoe Komlodi     qemu_fprintf(f, "slr=%x shr=%x\n", env->slr, env->shr);
1875fcf5ef2aSThomas Huth     for (i = 0; i < 32; i++) {
187690c84c56SMarkus Armbruster         qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]);
1877fcf5ef2aSThomas Huth         if ((i + 1) % 4 == 0)
187890c84c56SMarkus Armbruster             qemu_fprintf(f, "\n");
1879fcf5ef2aSThomas Huth         }
188090c84c56SMarkus Armbruster     qemu_fprintf(f, "\n\n");
1881fcf5ef2aSThomas Huth }
1882fcf5ef2aSThomas Huth 
1883fcf5ef2aSThomas Huth void mb_tcg_init(void)
1884fcf5ef2aSThomas Huth {
1885480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1886480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1887fcf5ef2aSThomas Huth 
1888480d29a8SRichard Henderson     static const struct {
1889480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1890480d29a8SRichard Henderson     } i32s[] = {
1891480d29a8SRichard Henderson         R(0),  R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1892480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1893480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1894480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1895480d29a8SRichard Henderson 
1896480d29a8SRichard Henderson         SP(pc),
1897480d29a8SRichard Henderson         SP(msr),
18981074c0fbSRichard Henderson         SP(msr_c),
1899480d29a8SRichard Henderson         SP(imm),
1900480d29a8SRichard Henderson         SP(iflags),
1901480d29a8SRichard Henderson         SP(btaken),
1902480d29a8SRichard Henderson         SP(btarget),
1903480d29a8SRichard Henderson         SP(res_val),
1904480d29a8SRichard Henderson     };
1905480d29a8SRichard Henderson 
1906480d29a8SRichard Henderson #undef R
1907480d29a8SRichard Henderson #undef SP
1908480d29a8SRichard Henderson 
1909480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1910480d29a8SRichard Henderson         *i32s[i].var =
1911480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1912fcf5ef2aSThomas Huth     }
191376e8187dSRichard Henderson 
1914480d29a8SRichard Henderson     cpu_res_addr =
1915480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1916fcf5ef2aSThomas Huth }
1917fcf5ef2aSThomas Huth 
1918fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1919fcf5ef2aSThomas Huth                           target_ulong *data)
1920fcf5ef2aSThomas Huth {
192176e8187dSRichard Henderson     env->pc = data[0];
1922fcf5ef2aSThomas Huth }
1923