xref: /openbmc/qemu/target/microblaze/translate.c (revision 9df297a2d84a0c452567ae6c2be2b5c42b8a0931)
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;
48b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
490f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
509b158558SRichard Henderson static TCGv_i32 cpu_iflags;
519b158558SRichard Henderson static TCGv cpu_res_addr;
529b158558SRichard Henderson static TCGv_i32 cpu_res_val;
53fcf5ef2aSThomas Huth 
54fcf5ef2aSThomas Huth #include "exec/gen-icount.h"
55fcf5ef2aSThomas Huth 
56fcf5ef2aSThomas Huth /* This is the state at translation time.  */
57fcf5ef2aSThomas Huth typedef struct DisasContext {
58d4705ae0SRichard Henderson     DisasContextBase base;
59fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu;
60fcf5ef2aSThomas Huth 
61683a247eSRichard Henderson     /* TCG op of the current insn_start.  */
62683a247eSRichard Henderson     TCGOp *insn_start;
63683a247eSRichard Henderson 
6420800179SRichard Henderson     TCGv_i32 r0;
6520800179SRichard Henderson     bool r0_set;
6620800179SRichard Henderson 
67fcf5ef2aSThomas Huth     /* Decoder.  */
68fcf5ef2aSThomas Huth     int type_b;
69fcf5ef2aSThomas Huth     uint32_t ir;
70d7ecb757SRichard Henderson     uint32_t ext_imm;
71fcf5ef2aSThomas Huth     uint8_t opcode;
72fcf5ef2aSThomas Huth     uint8_t rd, ra, rb;
73fcf5ef2aSThomas Huth     uint16_t imm;
74fcf5ef2aSThomas Huth 
75fcf5ef2aSThomas Huth     unsigned int cpustate_changed;
76683a247eSRichard Henderson     unsigned int tb_flags;
776f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
78287b1defSRichard Henderson     int mem_index;
79fcf5ef2aSThomas Huth 
80b9c58aabSRichard Henderson     /* Condition under which to jump, including NEVER and ALWAYS. */
81b9c58aabSRichard Henderson     TCGCond jmp_cond;
82b9c58aabSRichard Henderson 
83b9c58aabSRichard Henderson     /* Immediate branch-taken destination, or -1 for indirect. */
84b9c58aabSRichard Henderson     uint32_t jmp_dest;
85fcf5ef2aSThomas Huth 
86fcf5ef2aSThomas Huth     int abort_at_next_insn;
87fcf5ef2aSThomas Huth } DisasContext;
88fcf5ef2aSThomas Huth 
8920800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
9020800179SRichard Henderson {
9120800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
9220800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
9320800179SRichard Henderson     }
9420800179SRichard Henderson     return x;
9520800179SRichard Henderson }
9620800179SRichard Henderson 
9744d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9844d1432bSRichard Henderson #include "decode-insns.c.inc"
9944d1432bSRichard Henderson 
100683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
101fcf5ef2aSThomas Huth {
102fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
103683a247eSRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & ~MSR_TB_MASK) {
104683a247eSRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & ~MSR_TB_MASK);
105fcf5ef2aSThomas Huth     }
106fcf5ef2aSThomas Huth }
107fcf5ef2aSThomas Huth 
10841ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
109fcf5ef2aSThomas Huth {
110fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
111fcf5ef2aSThomas Huth 
112fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
113fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
114d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
115fcf5ef2aSThomas Huth }
116fcf5ef2aSThomas Huth 
11741ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
11841ba37c4SRichard Henderson {
11941ba37c4SRichard Henderson     t_sync_flags(dc);
120d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
12141ba37c4SRichard Henderson     gen_raise_exception(dc, index);
12241ba37c4SRichard Henderson }
12341ba37c4SRichard Henderson 
12441ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
12541ba37c4SRichard Henderson {
12641ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
12741ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
12841ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
12941ba37c4SRichard Henderson 
13041ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
13141ba37c4SRichard Henderson }
13241ba37c4SRichard Henderson 
133fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
134fcf5ef2aSThomas Huth {
135fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
136d4705ae0SRichard Henderson     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
137fcf5ef2aSThomas Huth #else
138fcf5ef2aSThomas Huth     return true;
139fcf5ef2aSThomas Huth #endif
140fcf5ef2aSThomas Huth }
141fcf5ef2aSThomas Huth 
142fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
143fcf5ef2aSThomas Huth {
144d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1450b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1460b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1470b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1480b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
1490b46fa08SRichard Henderson     } else if (use_goto_tb(dc, dest)) {
150fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1510f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
152d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
153fcf5ef2aSThomas Huth     } else {
1540f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
15507ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
156fcf5ef2aSThomas Huth     }
157d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
158fcf5ef2aSThomas Huth }
159fcf5ef2aSThomas Huth 
160bdfc1e88SEdgar E. Iglesias /*
1619ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1629ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1639ba8cd45SEdgar E. Iglesias  */
1649ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1659ba8cd45SEdgar E. Iglesias {
1662c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1675143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
16841ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1699ba8cd45SEdgar E. Iglesias     }
1709ba8cd45SEdgar E. Iglesias     return cond;
1719ba8cd45SEdgar E. Iglesias }
1729ba8cd45SEdgar E. Iglesias 
1739ba8cd45SEdgar E. Iglesias /*
174bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
175bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
176bdfc1e88SEdgar E. Iglesias  */
177bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
178bdfc1e88SEdgar E. Iglesias {
179287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
180bdfc1e88SEdgar E. Iglesias 
1812c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
18241ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
183bdfc1e88SEdgar E. Iglesias     }
184bdfc1e88SEdgar E. Iglesias     return cond_user;
185bdfc1e88SEdgar E. Iglesias }
186bdfc1e88SEdgar E. Iglesias 
187d7ecb757SRichard Henderson static int32_t dec_alu_typeb_imm(DisasContext *dc)
188fcf5ef2aSThomas Huth {
189d7ecb757SRichard Henderson     tcg_debug_assert(dc->type_b);
19020800179SRichard Henderson     return typeb_imm(dc, (int16_t)dc->imm);
191fcf5ef2aSThomas Huth }
192fcf5ef2aSThomas Huth 
193cfeea807SEdgar E. Iglesias static inline TCGv_i32 *dec_alu_op_b(DisasContext *dc)
194fcf5ef2aSThomas Huth {
195fcf5ef2aSThomas Huth     if (dc->type_b) {
196d7ecb757SRichard Henderson         tcg_gen_movi_i32(cpu_imm, dec_alu_typeb_imm(dc));
1979b158558SRichard Henderson         return &cpu_imm;
198d7ecb757SRichard Henderson     }
199fcf5ef2aSThomas Huth     return &cpu_R[dc->rb];
200fcf5ef2aSThomas Huth }
201fcf5ef2aSThomas Huth 
20220800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
203fcf5ef2aSThomas Huth {
20420800179SRichard Henderson     if (likely(reg != 0)) {
20520800179SRichard Henderson         return cpu_R[reg];
206fcf5ef2aSThomas Huth     }
20720800179SRichard Henderson     if (!dc->r0_set) {
20820800179SRichard Henderson         if (dc->r0 == NULL) {
20920800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
210fcf5ef2aSThomas Huth         }
21120800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
21220800179SRichard Henderson         dc->r0_set = true;
21320800179SRichard Henderson     }
21420800179SRichard Henderson     return dc->r0;
215fcf5ef2aSThomas Huth }
216fcf5ef2aSThomas Huth 
21720800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
21820800179SRichard Henderson {
21920800179SRichard Henderson     if (likely(reg != 0)) {
22020800179SRichard Henderson         return cpu_R[reg];
22120800179SRichard Henderson     }
22220800179SRichard Henderson     if (dc->r0 == NULL) {
22320800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
22420800179SRichard Henderson     }
22520800179SRichard Henderson     return dc->r0;
226fcf5ef2aSThomas Huth }
227fcf5ef2aSThomas Huth 
22820800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
22920800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
23020800179SRichard Henderson {
23120800179SRichard Henderson     TCGv_i32 rd, ra, rb;
23220800179SRichard Henderson 
23320800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
23420800179SRichard Henderson         return true;
235fcf5ef2aSThomas Huth     }
23620800179SRichard Henderson 
23720800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
23820800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
23920800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
24020800179SRichard Henderson     fn(rd, ra, rb);
24120800179SRichard Henderson     return true;
24220800179SRichard Henderson }
24320800179SRichard Henderson 
24439cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
24539cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
24639cf3864SRichard Henderson {
24739cf3864SRichard Henderson     TCGv_i32 rd, ra;
24839cf3864SRichard Henderson 
24939cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
25039cf3864SRichard Henderson         return true;
25139cf3864SRichard Henderson     }
25239cf3864SRichard Henderson 
25339cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
25439cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
25539cf3864SRichard Henderson     fn(rd, ra);
25639cf3864SRichard Henderson     return true;
25739cf3864SRichard Henderson }
25839cf3864SRichard Henderson 
25920800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
26020800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
26120800179SRichard Henderson {
26220800179SRichard Henderson     TCGv_i32 rd, ra;
26320800179SRichard Henderson 
26420800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
26520800179SRichard Henderson         return true;
26620800179SRichard Henderson     }
26720800179SRichard Henderson 
26820800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26920800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
27020800179SRichard Henderson     fni(rd, ra, arg->imm);
27120800179SRichard Henderson     return true;
27220800179SRichard Henderson }
27320800179SRichard Henderson 
27420800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
27520800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
27620800179SRichard Henderson {
27720800179SRichard Henderson     TCGv_i32 rd, ra, imm;
27820800179SRichard Henderson 
27920800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
28020800179SRichard Henderson         return true;
28120800179SRichard Henderson     }
28220800179SRichard Henderson 
28320800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
28420800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
28520800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
28620800179SRichard Henderson 
28720800179SRichard Henderson     fn(rd, ra, imm);
28820800179SRichard Henderson 
28920800179SRichard Henderson     tcg_temp_free_i32(imm);
29020800179SRichard Henderson     return true;
29120800179SRichard Henderson }
29220800179SRichard Henderson 
29320800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
29420800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
29520800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
29620800179SRichard Henderson 
297607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
298607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
299607f5767SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); }
300607f5767SRichard Henderson 
30139cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
30239cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
30339cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
30439cf3864SRichard Henderson 
30539cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
30639cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
30739cf3864SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); }
30839cf3864SRichard Henderson 
30920800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
31020800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
31120800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
31220800179SRichard Henderson 
31397955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
31497955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
31597955cebSRichard Henderson     { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); }
31697955cebSRichard Henderson 
31720800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
31820800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
31920800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
32020800179SRichard Henderson 
321d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
322d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
323d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
324d5aead3dSRichard Henderson 
325d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
326d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
327d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
328d5aead3dSRichard Henderson 
32920800179SRichard Henderson /* No input carry, but output carry. */
33020800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
33120800179SRichard Henderson {
33220800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
33320800179SRichard Henderson 
33420800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
33520800179SRichard Henderson 
33620800179SRichard Henderson     tcg_temp_free_i32(zero);
33720800179SRichard Henderson }
33820800179SRichard Henderson 
33920800179SRichard Henderson /* Input and output carry. */
34020800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
34120800179SRichard Henderson {
34220800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
34320800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
34420800179SRichard Henderson 
34520800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
34620800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
34720800179SRichard Henderson 
34820800179SRichard Henderson     tcg_temp_free_i32(tmp);
34920800179SRichard Henderson     tcg_temp_free_i32(zero);
35020800179SRichard Henderson }
35120800179SRichard Henderson 
35220800179SRichard Henderson /* Input carry, but no output carry. */
35320800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
35420800179SRichard Henderson {
35520800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
35620800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
35720800179SRichard Henderson }
35820800179SRichard Henderson 
35920800179SRichard Henderson DO_TYPEA(add, true, gen_add)
36020800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
36120800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
36220800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
36320800179SRichard Henderson 
36420800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
36520800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
36620800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
36720800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
36820800179SRichard Henderson 
369cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
370cb0a0a4cSRichard Henderson {
371cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
372cb0a0a4cSRichard Henderson }
373cb0a0a4cSRichard Henderson 
374cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
375cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
376cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
377cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
378cb0a0a4cSRichard Henderson 
379081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
380081d8e02SRichard Henderson {
381081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
382081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
383081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
384081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
385081d8e02SRichard Henderson }
386081d8e02SRichard Henderson 
387081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
388081d8e02SRichard Henderson {
389081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
390081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
391081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
392081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
393081d8e02SRichard Henderson }
394081d8e02SRichard Henderson 
395081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
396081d8e02SRichard Henderson {
397081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
398081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
399081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
400081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
401081d8e02SRichard Henderson }
402081d8e02SRichard Henderson 
403081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
404081d8e02SRichard Henderson {
405081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
406081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
407081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
408081d8e02SRichard Henderson 
409081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
410081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
411081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
412081d8e02SRichard Henderson                       imm_w, imm_s);
413081d8e02SRichard Henderson     } else {
414081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
415081d8e02SRichard Henderson     }
416081d8e02SRichard Henderson }
417081d8e02SRichard Henderson 
418081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
419081d8e02SRichard Henderson {
420081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
421081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
422081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
423081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
424081d8e02SRichard Henderson 
425081d8e02SRichard Henderson     if (imm_w < imm_s) {
426081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
427081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
428081d8e02SRichard Henderson                       imm_w, imm_s);
429081d8e02SRichard Henderson     } else {
430081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
431081d8e02SRichard Henderson     }
432081d8e02SRichard Henderson }
433081d8e02SRichard Henderson 
434081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
435081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
436081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
437081d8e02SRichard Henderson 
438081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
439081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
440081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
441081d8e02SRichard Henderson 
442081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
443081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
444081d8e02SRichard Henderson 
44539cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
44639cf3864SRichard Henderson {
44739cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
44839cf3864SRichard Henderson }
44939cf3864SRichard Henderson 
45039cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
45139cf3864SRichard Henderson 
45258b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
45358b48b63SRichard Henderson {
45458b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
45558b48b63SRichard Henderson 
45658b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
45758b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
45858b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
45958b48b63SRichard Henderson     tcg_temp_free_i32(lt);
46058b48b63SRichard Henderson }
46158b48b63SRichard Henderson 
46258b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
46358b48b63SRichard Henderson {
46458b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
46558b48b63SRichard Henderson 
46658b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
46758b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
46858b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
46958b48b63SRichard Henderson     tcg_temp_free_i32(lt);
47058b48b63SRichard Henderson }
47158b48b63SRichard Henderson 
47258b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
47358b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
474a2b0b90eSRichard Henderson 
475d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
476d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
477d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
478d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
479d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
480d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
481d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
482d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
483d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
484d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
485d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
486d5aead3dSRichard Henderson 
487d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
488d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
489d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
490d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
491d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
492d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
493d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
494d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
495d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
496d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
497d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
498d5aead3dSRichard Henderson 
499d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
500d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
501d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
502d5aead3dSRichard Henderson 
503d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
504d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
505d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
506d5aead3dSRichard Henderson 
507d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
508b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
509b1354342SRichard Henderson {
510b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
511b1354342SRichard Henderson }
512b1354342SRichard Henderson 
513b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
514b1354342SRichard Henderson {
515b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
516b1354342SRichard Henderson }
517b1354342SRichard Henderson 
518b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
519b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
520b1354342SRichard Henderson 
521e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
522e64b2e5cSRichard Henderson {
523e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
524e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
5256f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
526e64b2e5cSRichard Henderson     return true;
527e64b2e5cSRichard Henderson }
528e64b2e5cSRichard Henderson 
52997955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
53097955cebSRichard Henderson {
53197955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
53297955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
53397955cebSRichard Henderson     tcg_temp_free_i32(tmp);
53497955cebSRichard Henderson }
53597955cebSRichard Henderson 
53697955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
53797955cebSRichard Henderson {
53897955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
53997955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
54097955cebSRichard Henderson     tcg_temp_free_i32(tmp);
54197955cebSRichard Henderson }
54297955cebSRichard Henderson 
54397955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
54497955cebSRichard Henderson {
54597955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
54697955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
54797955cebSRichard Henderson     tcg_temp_free_i32(tmp);
54897955cebSRichard Henderson }
54997955cebSRichard Henderson 
55097955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
55197955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
55297955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
55397955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
55497955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
55597955cebSRichard Henderson 
556cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
557cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
558cb0a0a4cSRichard Henderson 
559607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
560607f5767SRichard Henderson {
561607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
562607f5767SRichard Henderson }
563607f5767SRichard Henderson 
564607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
565607f5767SRichard Henderson {
566607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
567607f5767SRichard Henderson }
568607f5767SRichard Henderson 
569607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
570607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
571607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
572607f5767SRichard Henderson 
573a2b0b90eSRichard Henderson /* No input carry, but output carry. */
574a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
575a2b0b90eSRichard Henderson {
576a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
577a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
578a2b0b90eSRichard Henderson }
579a2b0b90eSRichard Henderson 
580a2b0b90eSRichard Henderson /* Input and output carry. */
581a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
582a2b0b90eSRichard Henderson {
583a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
584a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
585a2b0b90eSRichard Henderson 
586a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
587a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
588a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
589a2b0b90eSRichard Henderson 
590a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
591a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
592a2b0b90eSRichard Henderson }
593a2b0b90eSRichard Henderson 
594a2b0b90eSRichard Henderson /* No input or output carry. */
595a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
596a2b0b90eSRichard Henderson {
597a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
598a2b0b90eSRichard Henderson }
599a2b0b90eSRichard Henderson 
600a2b0b90eSRichard Henderson /* Input carry, no output carry. */
601a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
602a2b0b90eSRichard Henderson {
603a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
604a2b0b90eSRichard Henderson 
605a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
606a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
607a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
608a2b0b90eSRichard Henderson 
609a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
610a2b0b90eSRichard Henderson }
611a2b0b90eSRichard Henderson 
612a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
613a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
614a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
615a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
616a2b0b90eSRichard Henderson 
617a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
618a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
619a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
620a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
621a2b0b90eSRichard Henderson 
62239cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
62339cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
62439cf3864SRichard Henderson 
62539cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
62639cf3864SRichard Henderson {
62739cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
62839cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
62939cf3864SRichard Henderson }
63039cf3864SRichard Henderson 
63139cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
63239cf3864SRichard Henderson {
63339cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
63439cf3864SRichard Henderson 
63539cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
63639cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
63739cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
63839cf3864SRichard Henderson 
63939cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
64039cf3864SRichard Henderson }
64139cf3864SRichard Henderson 
64239cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
64339cf3864SRichard Henderson {
64439cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
64539cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
64639cf3864SRichard Henderson }
64739cf3864SRichard Henderson 
64839cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
64939cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
65039cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
65139cf3864SRichard Henderson 
65239cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
65339cf3864SRichard Henderson {
65439cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
65539cf3864SRichard Henderson }
65639cf3864SRichard Henderson 
65739cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
65839cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
65939cf3864SRichard Henderson 
66039cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
66139cf3864SRichard Henderson {
66239cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
66339cf3864SRichard Henderson     trap_userspace(dc, true);
66439cf3864SRichard Henderson     return true;
66539cf3864SRichard Henderson }
66639cf3864SRichard Henderson 
667cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
668cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
669cb0a0a4cSRichard Henderson 
670d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
671d8e59c4aSRichard Henderson {
672d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
673d8e59c4aSRichard Henderson 
674d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
675d8e59c4aSRichard Henderson     if (ra && rb) {
676d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
677d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
678d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
679d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
680d8e59c4aSRichard Henderson     } else if (ra) {
681d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
682d8e59c4aSRichard Henderson     } else if (rb) {
683d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
684d8e59c4aSRichard Henderson     } else {
685d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
686d8e59c4aSRichard Henderson     }
687d8e59c4aSRichard Henderson 
688d8e59c4aSRichard Henderson     if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) {
689d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
690d8e59c4aSRichard Henderson     }
691d8e59c4aSRichard Henderson     return ret;
692d8e59c4aSRichard Henderson }
693d8e59c4aSRichard Henderson 
694d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
695d8e59c4aSRichard Henderson {
696d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
697d8e59c4aSRichard Henderson 
698d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
699d8e59c4aSRichard Henderson     if (ra) {
700d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
701d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
702d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
703d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
704d8e59c4aSRichard Henderson     } else {
705d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
706d8e59c4aSRichard Henderson     }
707d8e59c4aSRichard Henderson 
708d8e59c4aSRichard Henderson     if (ra == 1 && dc->cpu->cfg.stackprot) {
709d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
710d8e59c4aSRichard Henderson     }
711d8e59c4aSRichard Henderson     return ret;
712d8e59c4aSRichard Henderson }
713d8e59c4aSRichard Henderson 
714d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
715d8e59c4aSRichard Henderson {
716d8e59c4aSRichard Henderson     int addr_size = dc->cpu->cfg.addr_size;
717d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
718d8e59c4aSRichard Henderson 
719d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
720d8e59c4aSRichard Henderson         if (rb) {
721d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
722d8e59c4aSRichard Henderson         } else {
723d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
724d8e59c4aSRichard Henderson         }
725d8e59c4aSRichard Henderson     } else {
726d8e59c4aSRichard Henderson         if (rb) {
727d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
728d8e59c4aSRichard Henderson         } else {
729d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
730d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
731d8e59c4aSRichard Henderson         }
732d8e59c4aSRichard Henderson         if (addr_size < 64) {
733d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
734d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
735d8e59c4aSRichard Henderson         }
736d8e59c4aSRichard Henderson     }
737d8e59c4aSRichard Henderson     return ret;
738d8e59c4aSRichard Henderson }
739d8e59c4aSRichard Henderson 
740ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
741ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
742ab0c8d0fSRichard Henderson {
743ab0c8d0fSRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
744ab0c8d0fSRichard Henderson 
745ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
746ab0c8d0fSRichard Henderson     iflags |= rd << 5;
747ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
748ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
749ab0c8d0fSRichard Henderson 
750ab0c8d0fSRichard Henderson     tcg_set_insn_start_param(dc->insn_start, 1, iflags);
751ab0c8d0fSRichard Henderson }
752ab0c8d0fSRichard Henderson 
753d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
754d8e59c4aSRichard Henderson                     int mem_index, bool rev)
755d8e59c4aSRichard Henderson {
756d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
757d8e59c4aSRichard Henderson 
758d8e59c4aSRichard Henderson     /*
759d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
760d8e59c4aSRichard Henderson      *
761d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
762d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
763d8e59c4aSRichard Henderson      */
764d8e59c4aSRichard Henderson     if (rev) {
765d8e59c4aSRichard Henderson         if (size > MO_8) {
766d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
767d8e59c4aSRichard Henderson         }
768d8e59c4aSRichard Henderson         if (size < MO_32) {
769d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
770d8e59c4aSRichard Henderson         }
771d8e59c4aSRichard Henderson     }
772d8e59c4aSRichard Henderson 
773ab0c8d0fSRichard Henderson     if (size > MO_8 &&
774ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
775ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
776ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
777ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
778d8e59c4aSRichard Henderson     }
779d8e59c4aSRichard Henderson 
780ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
781d8e59c4aSRichard Henderson 
782d8e59c4aSRichard Henderson     tcg_temp_free(addr);
783d8e59c4aSRichard Henderson     return true;
784d8e59c4aSRichard Henderson }
785d8e59c4aSRichard Henderson 
786d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
787d8e59c4aSRichard Henderson {
788d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
789d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
790d8e59c4aSRichard Henderson }
791d8e59c4aSRichard Henderson 
792d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
793d8e59c4aSRichard Henderson {
794d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
795d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
796d8e59c4aSRichard Henderson }
797d8e59c4aSRichard Henderson 
798d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
799d8e59c4aSRichard Henderson {
800d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
801d8e59c4aSRichard Henderson         return true;
802d8e59c4aSRichard Henderson     }
803d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
804d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
805d8e59c4aSRichard Henderson }
806d8e59c4aSRichard Henderson 
807d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
808d8e59c4aSRichard Henderson {
809d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
810d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
811d8e59c4aSRichard Henderson }
812d8e59c4aSRichard Henderson 
813d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
814d8e59c4aSRichard Henderson {
815d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
816d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
817d8e59c4aSRichard Henderson }
818d8e59c4aSRichard Henderson 
819d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
820d8e59c4aSRichard Henderson {
821d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
822d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
823d8e59c4aSRichard Henderson }
824d8e59c4aSRichard Henderson 
825d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
826d8e59c4aSRichard Henderson {
827d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
828d8e59c4aSRichard Henderson         return true;
829d8e59c4aSRichard Henderson     }
830d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
831d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
832d8e59c4aSRichard Henderson }
833d8e59c4aSRichard Henderson 
834d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
835d8e59c4aSRichard Henderson {
836d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
837d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
838d8e59c4aSRichard Henderson }
839d8e59c4aSRichard Henderson 
840d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
841d8e59c4aSRichard Henderson {
842d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
843d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
844d8e59c4aSRichard Henderson }
845d8e59c4aSRichard Henderson 
846d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
847d8e59c4aSRichard Henderson {
848d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
849d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
850d8e59c4aSRichard Henderson }
851d8e59c4aSRichard Henderson 
852d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
853d8e59c4aSRichard Henderson {
854d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
855d8e59c4aSRichard Henderson         return true;
856d8e59c4aSRichard Henderson     }
857d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
858d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
859d8e59c4aSRichard Henderson }
860d8e59c4aSRichard Henderson 
861d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
862d8e59c4aSRichard Henderson {
863d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
864d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
865d8e59c4aSRichard Henderson }
866d8e59c4aSRichard Henderson 
867d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
868d8e59c4aSRichard Henderson {
869d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
870d8e59c4aSRichard Henderson 
871d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
872d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
873d8e59c4aSRichard Henderson 
874d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
875d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
876d8e59c4aSRichard Henderson     tcg_temp_free(addr);
877d8e59c4aSRichard Henderson 
878d8e59c4aSRichard Henderson     if (arg->rd) {
879d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
880d8e59c4aSRichard Henderson     }
881d8e59c4aSRichard Henderson 
882d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
883d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
884d8e59c4aSRichard Henderson     return true;
885d8e59c4aSRichard Henderson }
886d8e59c4aSRichard Henderson 
887d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
888d8e59c4aSRichard Henderson                      int mem_index, bool rev)
889d8e59c4aSRichard Henderson {
890d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
891d8e59c4aSRichard Henderson 
892d8e59c4aSRichard Henderson     /*
893d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
894d8e59c4aSRichard Henderson      *
895d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
896d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
897d8e59c4aSRichard Henderson      */
898d8e59c4aSRichard Henderson     if (rev) {
899d8e59c4aSRichard Henderson         if (size > MO_8) {
900d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
901d8e59c4aSRichard Henderson         }
902d8e59c4aSRichard Henderson         if (size < MO_32) {
903d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
904d8e59c4aSRichard Henderson         }
905d8e59c4aSRichard Henderson     }
906d8e59c4aSRichard Henderson 
907ab0c8d0fSRichard Henderson     if (size > MO_8 &&
908ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
909ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
910ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
911ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
912d8e59c4aSRichard Henderson     }
913d8e59c4aSRichard Henderson 
914ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
915ab0c8d0fSRichard Henderson 
916d8e59c4aSRichard Henderson     tcg_temp_free(addr);
917d8e59c4aSRichard Henderson     return true;
918d8e59c4aSRichard Henderson }
919d8e59c4aSRichard Henderson 
920d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
921d8e59c4aSRichard Henderson {
922d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
923d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
924d8e59c4aSRichard Henderson }
925d8e59c4aSRichard Henderson 
926d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
927d8e59c4aSRichard Henderson {
928d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
929d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
930d8e59c4aSRichard Henderson }
931d8e59c4aSRichard Henderson 
932d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
933d8e59c4aSRichard Henderson {
934d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
935d8e59c4aSRichard Henderson         return true;
936d8e59c4aSRichard Henderson     }
937d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
938d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
939d8e59c4aSRichard Henderson }
940d8e59c4aSRichard Henderson 
941d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
942d8e59c4aSRichard Henderson {
943d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
944d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
945d8e59c4aSRichard Henderson }
946d8e59c4aSRichard Henderson 
947d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
948d8e59c4aSRichard Henderson {
949d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
950d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
951d8e59c4aSRichard Henderson }
952d8e59c4aSRichard Henderson 
953d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
954d8e59c4aSRichard Henderson {
955d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
956d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
957d8e59c4aSRichard Henderson }
958d8e59c4aSRichard Henderson 
959d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
960d8e59c4aSRichard Henderson {
961d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
962d8e59c4aSRichard Henderson         return true;
963d8e59c4aSRichard Henderson     }
964d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
965d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
966d8e59c4aSRichard Henderson }
967d8e59c4aSRichard Henderson 
968d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
969d8e59c4aSRichard Henderson {
970d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
971d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
972d8e59c4aSRichard Henderson }
973d8e59c4aSRichard Henderson 
974d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
975d8e59c4aSRichard Henderson {
976d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
977d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
978d8e59c4aSRichard Henderson }
979d8e59c4aSRichard Henderson 
980d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
981d8e59c4aSRichard Henderson {
982d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
983d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
984d8e59c4aSRichard Henderson }
985d8e59c4aSRichard Henderson 
986d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
987d8e59c4aSRichard Henderson {
988d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
989d8e59c4aSRichard Henderson         return true;
990d8e59c4aSRichard Henderson     }
991d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
992d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
993d8e59c4aSRichard Henderson }
994d8e59c4aSRichard Henderson 
995d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
996d8e59c4aSRichard Henderson {
997d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
998d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
999d8e59c4aSRichard Henderson }
1000d8e59c4aSRichard Henderson 
1001d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1002d8e59c4aSRichard Henderson {
1003d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1004d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1005d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1006d8e59c4aSRichard Henderson     TCGv_i32 tval;
1007d8e59c4aSRichard Henderson 
1008d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1009d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1010d8e59c4aSRichard Henderson 
1011d8e59c4aSRichard Henderson     /*
1012d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1013d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1014d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1015d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1016d8e59c4aSRichard Henderson      */
1017d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1018d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1019d8e59c4aSRichard Henderson 
1020d8e59c4aSRichard Henderson     /*
1021d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1022d8e59c4aSRichard Henderson      * the reserved location.
1023d8e59c4aSRichard Henderson      */
1024d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1025d8e59c4aSRichard Henderson 
1026d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1027d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1028d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1029d8e59c4aSRichard Henderson 
1030d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1031d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1032d8e59c4aSRichard Henderson 
1033d8e59c4aSRichard Henderson     /* Success */
1034d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1035d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1036d8e59c4aSRichard Henderson 
1037d8e59c4aSRichard Henderson     /* Failure */
1038d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1039d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1040d8e59c4aSRichard Henderson 
1041d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1042d8e59c4aSRichard Henderson 
1043d8e59c4aSRichard Henderson     /*
1044d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1045d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1046d8e59c4aSRichard Henderson      */
1047d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1048d8e59c4aSRichard Henderson     return true;
1049d8e59c4aSRichard Henderson }
1050d8e59c4aSRichard Henderson 
105116bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
105216bbbbc9SRichard Henderson {
105316bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
105416bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
105516bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
105616bbbbc9SRichard Henderson     }
105716bbbbc9SRichard Henderson }
105816bbbbc9SRichard Henderson 
105916bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
106016bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
106116bbbbc9SRichard Henderson {
106216bbbbc9SRichard Henderson     uint32_t add_pc;
106316bbbbc9SRichard Henderson 
106416bbbbc9SRichard Henderson     if (delay) {
106516bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
106616bbbbc9SRichard Henderson     }
106716bbbbc9SRichard Henderson 
106816bbbbc9SRichard Henderson     if (link) {
106916bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
107016bbbbc9SRichard Henderson     }
107116bbbbc9SRichard Henderson 
107216bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
107316bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
107416bbbbc9SRichard Henderson     if (dest_rb > 0) {
107516bbbbc9SRichard Henderson         dc->jmp_dest = -1;
107616bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
107716bbbbc9SRichard Henderson     } else {
107816bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
107916bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
108016bbbbc9SRichard Henderson     }
108116bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
108216bbbbc9SRichard Henderson     return true;
108316bbbbc9SRichard Henderson }
108416bbbbc9SRichard Henderson 
108516bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
108616bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
108716bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
108816bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
108916bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
109016bbbbc9SRichard Henderson 
109116bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
109216bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
109316bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
109416bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
109516bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
109616bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
109716bbbbc9SRichard Henderson 
1098fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1099fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1100fd779113SRichard Henderson {
1101fd779113SRichard Henderson     TCGv_i32 zero, next;
1102fd779113SRichard Henderson 
1103fd779113SRichard Henderson     if (delay) {
1104fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1105fd779113SRichard Henderson     }
1106fd779113SRichard Henderson 
1107fd779113SRichard Henderson     dc->jmp_cond = cond;
1108fd779113SRichard Henderson 
1109fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1110fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1111fd779113SRichard Henderson 
1112fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1113fd779113SRichard Henderson     if (dest_rb > 0) {
1114fd779113SRichard Henderson         dc->jmp_dest = -1;
1115fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1116fd779113SRichard Henderson     } else {
1117fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1118fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1119fd779113SRichard Henderson     }
1120fd779113SRichard Henderson 
1121fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1122fd779113SRichard Henderson     zero = tcg_const_i32(0);
1123fd779113SRichard Henderson     next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4);
1124fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1125fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1126fd779113SRichard Henderson                         cpu_btarget, next);
1127fd779113SRichard Henderson     tcg_temp_free_i32(zero);
1128fd779113SRichard Henderson     tcg_temp_free_i32(next);
1129fd779113SRichard Henderson 
1130fd779113SRichard Henderson     return true;
1131fd779113SRichard Henderson }
1132fd779113SRichard Henderson 
1133fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1134fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1135fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1136fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1137fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1138fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1139fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1140fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1141fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1142fd779113SRichard Henderson 
1143fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1144fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1145fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1146fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1147fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1148fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1149fd779113SRichard Henderson 
1150f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1151f5235314SRichard Henderson {
1152f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1153f5235314SRichard Henderson         return true;
1154f5235314SRichard Henderson     }
1155f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1156f5235314SRichard Henderson     if (arg->rd) {
1157f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1158f5235314SRichard Henderson     }
1159f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1160f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1161f5235314SRichard Henderson 
1162f5235314SRichard Henderson     dc->base.is_jmp = DISAS_UPDATE;
1163f5235314SRichard Henderson     return true;
1164f5235314SRichard Henderson }
1165f5235314SRichard Henderson 
1166f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1167f5235314SRichard Henderson {
1168f5235314SRichard Henderson     uint32_t imm = arg->imm;
1169f5235314SRichard Henderson 
1170f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1171f5235314SRichard Henderson         return true;
1172f5235314SRichard Henderson     }
1173f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1174f5235314SRichard Henderson     if (arg->rd) {
1175f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1176f5235314SRichard Henderson     }
1177f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1178f5235314SRichard Henderson 
1179f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1180f5235314SRichard Henderson     switch (imm) {
1181f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1182f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1183f5235314SRichard Henderson         break;
1184f5235314SRichard Henderson     case 0x18: /* debug trap */
1185f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1186f5235314SRichard Henderson         break;
1187f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1188f5235314SRichard Henderson         g_assert_not_reached();
1189f5235314SRichard Henderson     }
1190f5235314SRichard Henderson #else
1191f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1192f5235314SRichard Henderson 
1193f5235314SRichard Henderson     if (imm != 0x18) {
1194f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1195f5235314SRichard Henderson     }
1196f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1197f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1198f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1199f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1200f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1201f5235314SRichard Henderson     }
1202f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
1203f5235314SRichard Henderson     dc->base.is_jmp = DISAS_UPDATE;
1204f5235314SRichard Henderson #endif
1205f5235314SRichard Henderson 
1206f5235314SRichard Henderson     return true;
1207f5235314SRichard Henderson }
1208f5235314SRichard Henderson 
1209ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1210ee8c7f9fSRichard Henderson {
1211ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1212ee8c7f9fSRichard Henderson 
1213ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1214ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1215ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1216ee8c7f9fSRichard Henderson     }
1217ee8c7f9fSRichard Henderson 
1218ee8c7f9fSRichard Henderson     /* Sleep. */
1219ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1220ee8c7f9fSRichard Henderson         TCGv_i32 tmp_1;
1221ee8c7f9fSRichard Henderson 
1222ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1223ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1224ee8c7f9fSRichard Henderson             return true;
1225ee8c7f9fSRichard Henderson         }
1226ee8c7f9fSRichard Henderson 
1227ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1228ee8c7f9fSRichard Henderson 
1229ee8c7f9fSRichard Henderson         tmp_1 = tcg_const_i32(1);
1230ee8c7f9fSRichard Henderson         tcg_gen_st_i32(tmp_1, cpu_env,
1231ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1232ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1233ee8c7f9fSRichard Henderson         tcg_temp_free_i32(tmp_1);
1234ee8c7f9fSRichard Henderson 
1235ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1236ee8c7f9fSRichard Henderson 
1237ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1238ee8c7f9fSRichard Henderson     }
1239ee8c7f9fSRichard Henderson 
1240ee8c7f9fSRichard Henderson     /*
1241ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1242ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1243ee8c7f9fSRichard Henderson      * code immediately.
1244ee8c7f9fSRichard Henderson      *
1245ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1246ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1247ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1248ee8c7f9fSRichard Henderson      *
1249ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1250ee8c7f9fSRichard Henderson      */
1251ee8c7f9fSRichard Henderson     dc->cpustate_changed = 1;
1252ee8c7f9fSRichard Henderson     return true;
1253ee8c7f9fSRichard Henderson }
1254ee8c7f9fSRichard Henderson 
1255e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1256e6cb0354SRichard Henderson {
1257e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1258e6cb0354SRichard Henderson         return true;
1259e6cb0354SRichard Henderson     }
1260e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1261e6cb0354SRichard Henderson     setup_dslot(dc, true);
1262e6cb0354SRichard Henderson 
1263e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1264e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1265e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1266e6cb0354SRichard Henderson     return true;
1267e6cb0354SRichard Henderson }
1268e6cb0354SRichard Henderson 
1269e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1270e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1271e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1272e6cb0354SRichard Henderson 
1273e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1274e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1275e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1276e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1277e6cb0354SRichard Henderson 
127820800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
127920800179SRichard Henderson {
128020800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
128120800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
128220800179SRichard Henderson         trap_illegal(dc, true);
128320800179SRichard Henderson         return true;
128420800179SRichard Henderson     }
128520800179SRichard Henderson     /*
128620800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
128720800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
128820800179SRichard Henderson      */
128920800179SRichard Henderson     return false;
1290fcf5ef2aSThomas Huth }
1291fcf5ef2aSThomas Huth 
12921074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1293fcf5ef2aSThomas Huth {
12941074c0fbSRichard Henderson     TCGv_i32 t;
12951074c0fbSRichard Henderson 
12961074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
12971074c0fbSRichard Henderson     t = tcg_temp_new_i32();
12981074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
12991074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
13001074c0fbSRichard Henderson     tcg_temp_free_i32(t);
1301fcf5ef2aSThomas Huth }
1302fcf5ef2aSThomas Huth 
1303*9df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
13041074c0fbSRichard Henderson static void msr_write(DisasContext *dc, TCGv_i32 v)
1305fcf5ef2aSThomas Huth {
1306fcf5ef2aSThomas Huth     dc->cpustate_changed = 1;
13071074c0fbSRichard Henderson 
13081074c0fbSRichard Henderson     /* Install MSR_C.  */
13091074c0fbSRichard Henderson     tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
13101074c0fbSRichard Henderson 
13111074c0fbSRichard Henderson     /* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
13121074c0fbSRichard Henderson     tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
1313fcf5ef2aSThomas Huth }
1314*9df297a2SRichard Henderson #endif
1315fcf5ef2aSThomas Huth 
1316536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1317536e340fSRichard Henderson {
1318536e340fSRichard Henderson     uint32_t imm = arg->imm;
1319536e340fSRichard Henderson 
1320536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1321536e340fSRichard Henderson         return true;
1322536e340fSRichard Henderson     }
1323536e340fSRichard Henderson 
1324536e340fSRichard Henderson     if (arg->rd) {
1325536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1326536e340fSRichard Henderson     }
1327536e340fSRichard Henderson 
1328536e340fSRichard Henderson     /*
1329536e340fSRichard Henderson      * Handle the carry bit separately.
1330536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1331536e340fSRichard Henderson      */
1332536e340fSRichard Henderson     if (imm & MSR_C) {
1333536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1334536e340fSRichard Henderson     }
1335536e340fSRichard Henderson 
1336536e340fSRichard Henderson     /*
1337536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1338536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1339536e340fSRichard Henderson      */
1340536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1341536e340fSRichard Henderson 
1342536e340fSRichard Henderson     if (imm != 0) {
1343536e340fSRichard Henderson         if (set) {
1344536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1345536e340fSRichard Henderson         } else {
1346536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1347536e340fSRichard Henderson         }
1348536e340fSRichard Henderson         dc->cpustate_changed = 1;
1349536e340fSRichard Henderson     }
1350536e340fSRichard Henderson     return true;
1351536e340fSRichard Henderson }
1352536e340fSRichard Henderson 
1353536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1354536e340fSRichard Henderson {
1355536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1356536e340fSRichard Henderson }
1357536e340fSRichard Henderson 
1358536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1359536e340fSRichard Henderson {
1360536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1361536e340fSRichard Henderson }
1362536e340fSRichard Henderson 
1363*9df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
1364fcf5ef2aSThomas Huth {
1365*9df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
1366*9df297a2SRichard Henderson         return true;
1367f0f7e7f7SEdgar E. Iglesias     }
1368f0f7e7f7SEdgar E. Iglesias 
1369*9df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
1370*9df297a2SRichard Henderson     g_assert_not_reached();
1371*9df297a2SRichard Henderson #else
1372*9df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
1373*9df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
1374*9df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
1375*9df297a2SRichard Henderson         return true;
13762023e9a3SEdgar E. Iglesias     }
1377fcf5ef2aSThomas Huth 
1378*9df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
1379*9df297a2SRichard Henderson     switch (arg->rs) {
1380aa28e6d4SRichard Henderson     case SR_MSR:
1381*9df297a2SRichard Henderson         msr_write(dc, src);
1382fcf5ef2aSThomas Huth         break;
1383*9df297a2SRichard Henderson     case SR_FSR:
1384*9df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr));
1385*9df297a2SRichard Henderson         break;
1386*9df297a2SRichard Henderson     case 0x800:
1387*9df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr));
1388*9df297a2SRichard Henderson         break;
1389*9df297a2SRichard Henderson     case 0x802:
1390*9df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr));
1391*9df297a2SRichard Henderson         break;
1392*9df297a2SRichard Henderson 
1393*9df297a2SRichard Henderson     case 0x1000: /* PID */
1394*9df297a2SRichard Henderson     case 0x1001: /* ZPR */
1395*9df297a2SRichard Henderson     case 0x1002: /* TLBX */
1396*9df297a2SRichard Henderson     case 0x1003: /* TLBLO */
1397*9df297a2SRichard Henderson     case 0x1004: /* TLBHI */
1398*9df297a2SRichard Henderson     case 0x1005: /* TLBSX */
1399*9df297a2SRichard Henderson         {
1400*9df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
1401*9df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
1402*9df297a2SRichard Henderson 
1403*9df297a2SRichard Henderson             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src);
1404*9df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
1405*9df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
1406*9df297a2SRichard Henderson         }
1407*9df297a2SRichard Henderson         break;
1408*9df297a2SRichard Henderson 
1409*9df297a2SRichard Henderson     default:
1410*9df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
1411*9df297a2SRichard Henderson         return true;
1412*9df297a2SRichard Henderson     }
1413*9df297a2SRichard Henderson     dc->cpustate_changed = 1;
1414*9df297a2SRichard Henderson     return true;
1415*9df297a2SRichard Henderson #endif
1416*9df297a2SRichard Henderson }
1417*9df297a2SRichard Henderson 
1418*9df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
1419*9df297a2SRichard Henderson {
1420*9df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
1421*9df297a2SRichard Henderson 
1422*9df297a2SRichard Henderson     if (arg->e) {
1423*9df297a2SRichard Henderson         switch (arg->rs) {
1424351527b7SEdgar E. Iglesias         case SR_EAR:
1425dbdb77c4SRichard Henderson             {
1426dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
1427*9df297a2SRichard Henderson                 tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1428*9df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1429dbdb77c4SRichard Henderson                 tcg_temp_free_i64(t64);
1430dbdb77c4SRichard Henderson             }
1431*9df297a2SRichard Henderson             return true;
1432*9df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
1433*9df297a2SRichard Henderson         case 0x1003: /* TLBLO */
1434*9df297a2SRichard Henderson             /* Handled below. */
1435aa28e6d4SRichard Henderson             break;
1436*9df297a2SRichard Henderson #endif
1437*9df297a2SRichard Henderson         case 0x2006 ... 0x2009:
1438*9df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
1439*9df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
1440*9df297a2SRichard Henderson             return true;
1441fcf5ef2aSThomas Huth         default:
1442*9df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
1443*9df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
1444*9df297a2SRichard Henderson             return true;
1445fcf5ef2aSThomas Huth         }
1446*9df297a2SRichard Henderson     }
1447*9df297a2SRichard Henderson 
1448*9df297a2SRichard Henderson     switch (arg->rs) {
1449aa28e6d4SRichard Henderson     case SR_PC:
1450*9df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
1451fcf5ef2aSThomas Huth         break;
1452aa28e6d4SRichard Henderson     case SR_MSR:
1453*9df297a2SRichard Henderson         msr_read(dc, dest);
1454fcf5ef2aSThomas Huth         break;
1455351527b7SEdgar E. Iglesias     case SR_EAR:
1456dbdb77c4SRichard Henderson         {
1457dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1458dbdb77c4SRichard Henderson             tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
1459*9df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1460dbdb77c4SRichard Henderson             tcg_temp_free_i64(t64);
1461a1b48e3aSEdgar E. Iglesias         }
1462aa28e6d4SRichard Henderson         break;
1463351527b7SEdgar E. Iglesias     case SR_ESR:
1464*9df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr));
1465aa28e6d4SRichard Henderson         break;
1466351527b7SEdgar E. Iglesias     case SR_FSR:
1467*9df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr));
1468aa28e6d4SRichard Henderson         break;
1469351527b7SEdgar E. Iglesias     case SR_BTR:
1470*9df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr));
1471aa28e6d4SRichard Henderson         break;
14727cdae31dSTong Ho     case SR_EDR:
1473*9df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr));
1474fcf5ef2aSThomas Huth         break;
1475fcf5ef2aSThomas Huth     case 0x800:
1476*9df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr));
1477fcf5ef2aSThomas Huth         break;
1478fcf5ef2aSThomas Huth     case 0x802:
1479*9df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr));
1480fcf5ef2aSThomas Huth         break;
1481*9df297a2SRichard Henderson 
1482*9df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
1483*9df297a2SRichard Henderson     case 0x1000: /* PID */
1484*9df297a2SRichard Henderson     case 0x1001: /* ZPR */
1485*9df297a2SRichard Henderson     case 0x1002: /* TLBX */
1486*9df297a2SRichard Henderson     case 0x1003: /* TLBLO */
1487*9df297a2SRichard Henderson     case 0x1004: /* TLBHI */
1488*9df297a2SRichard Henderson     case 0x1005: /* TLBSX */
1489*9df297a2SRichard Henderson         {
1490*9df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
1491*9df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
1492*9df297a2SRichard Henderson 
1493*9df297a2SRichard Henderson             gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg);
1494*9df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
1495*9df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
1496*9df297a2SRichard Henderson         }
1497*9df297a2SRichard Henderson         break;
1498*9df297a2SRichard Henderson #endif
1499*9df297a2SRichard Henderson 
1500351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
1501*9df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env,
1502*9df297a2SRichard Henderson                        offsetof(CPUMBState, pvr.regs[arg->rs - 0x2000]));
1503fcf5ef2aSThomas Huth         break;
1504fcf5ef2aSThomas Huth     default:
1505*9df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1506fcf5ef2aSThomas Huth         break;
1507fcf5ef2aSThomas Huth     }
1508*9df297a2SRichard Henderson     return true;
1509fcf5ef2aSThomas Huth }
1510fcf5ef2aSThomas Huth 
15113fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
1512fcf5ef2aSThomas Huth {
15133fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1514fcf5ef2aSThomas Huth 
15153fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15163fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15173fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15183fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15193fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15203fb394fdSRichard Henderson 
15213fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1522fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1523fcf5ef2aSThomas Huth }
1524fcf5ef2aSThomas Huth 
15253fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
1526fcf5ef2aSThomas Huth {
15273fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1528fcf5ef2aSThomas Huth 
15293fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15303fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15313fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15323fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15333fb394fdSRichard Henderson 
15343fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1535fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1536fcf5ef2aSThomas Huth }
1537fcf5ef2aSThomas Huth 
15383fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
1539fcf5ef2aSThomas Huth {
15403fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1541fcf5ef2aSThomas Huth 
15423fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15433fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15443fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15453fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15463fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1547fcf5ef2aSThomas Huth 
15483fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1549fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1550fcf5ef2aSThomas Huth }
1551fcf5ef2aSThomas Huth 
1552fcf5ef2aSThomas Huth static void dec_null(DisasContext *dc)
1553fcf5ef2aSThomas Huth {
15549ba8cd45SEdgar E. Iglesias     if (trap_illegal(dc, true)) {
1555fcf5ef2aSThomas Huth         return;
1556fcf5ef2aSThomas Huth     }
1557d4705ae0SRichard Henderson     qemu_log_mask(LOG_GUEST_ERROR, "unknown insn pc=%x opc=%x\n",
1558d4705ae0SRichard Henderson                   (uint32_t)dc->base.pc_next, dc->opcode);
1559fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 1;
1560fcf5ef2aSThomas Huth }
1561fcf5ef2aSThomas Huth 
1562fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
1563fcf5ef2aSThomas Huth static void dec_stream(DisasContext *dc)
1564fcf5ef2aSThomas Huth {
1565fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1566fcf5ef2aSThomas Huth     int ctrl;
1567fcf5ef2aSThomas Huth 
1568bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
1569fcf5ef2aSThomas Huth         return;
1570fcf5ef2aSThomas Huth     }
1571fcf5ef2aSThomas Huth 
1572cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
1573fcf5ef2aSThomas Huth     if (dc->type_b) {
1574cfeea807SEdgar E. Iglesias         tcg_gen_movi_i32(t_id, dc->imm & 0xf);
1575fcf5ef2aSThomas Huth         ctrl = dc->imm >> 10;
1576fcf5ef2aSThomas Huth     } else {
1577cfeea807SEdgar E. Iglesias         tcg_gen_andi_i32(t_id, cpu_R[dc->rb], 0xf);
1578fcf5ef2aSThomas Huth         ctrl = dc->imm >> 5;
1579fcf5ef2aSThomas Huth     }
1580fcf5ef2aSThomas Huth 
1581cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
1582fcf5ef2aSThomas Huth 
1583fcf5ef2aSThomas Huth     if (dc->rd == 0) {
1584fcf5ef2aSThomas Huth         gen_helper_put(t_id, t_ctrl, cpu_R[dc->ra]);
1585fcf5ef2aSThomas Huth     } else {
1586fcf5ef2aSThomas Huth         gen_helper_get(cpu_R[dc->rd], t_id, t_ctrl);
1587fcf5ef2aSThomas Huth     }
1588cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1589cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
1590fcf5ef2aSThomas Huth }
1591fcf5ef2aSThomas Huth 
1592fcf5ef2aSThomas Huth static struct decoder_info {
1593fcf5ef2aSThomas Huth     struct {
1594fcf5ef2aSThomas Huth         uint32_t bits;
1595fcf5ef2aSThomas Huth         uint32_t mask;
1596fcf5ef2aSThomas Huth     };
1597fcf5ef2aSThomas Huth     void (*dec)(DisasContext *dc);
1598fcf5ef2aSThomas Huth } decinfo[] = {
1599fcf5ef2aSThomas Huth     {DEC_STREAM, dec_stream},
1600fcf5ef2aSThomas Huth     {{0, 0}, dec_null}
1601fcf5ef2aSThomas Huth };
1602fcf5ef2aSThomas Huth 
160344d1432bSRichard Henderson static void old_decode(DisasContext *dc, uint32_t ir)
1604fcf5ef2aSThomas Huth {
1605fcf5ef2aSThomas Huth     int i;
1606fcf5ef2aSThomas Huth 
1607fcf5ef2aSThomas Huth     dc->ir = ir;
1608fcf5ef2aSThomas Huth 
1609fcf5ef2aSThomas Huth     /* bit 2 seems to indicate insn type.  */
1610fcf5ef2aSThomas Huth     dc->type_b = ir & (1 << 29);
1611fcf5ef2aSThomas Huth 
1612fcf5ef2aSThomas Huth     dc->opcode = EXTRACT_FIELD(ir, 26, 31);
1613fcf5ef2aSThomas Huth     dc->rd = EXTRACT_FIELD(ir, 21, 25);
1614fcf5ef2aSThomas Huth     dc->ra = EXTRACT_FIELD(ir, 16, 20);
1615fcf5ef2aSThomas Huth     dc->rb = EXTRACT_FIELD(ir, 11, 15);
1616fcf5ef2aSThomas Huth     dc->imm = EXTRACT_FIELD(ir, 0, 15);
1617fcf5ef2aSThomas Huth 
1618fcf5ef2aSThomas Huth     /* Large switch for all insns.  */
1619fcf5ef2aSThomas Huth     for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
1620fcf5ef2aSThomas Huth         if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
1621fcf5ef2aSThomas Huth             decinfo[i].dec(dc);
1622fcf5ef2aSThomas Huth             break;
1623fcf5ef2aSThomas Huth         }
1624fcf5ef2aSThomas Huth     }
1625fcf5ef2aSThomas Huth }
1626fcf5ef2aSThomas Huth 
1627372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1628fcf5ef2aSThomas Huth {
1629372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1630372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1631372122e3SRichard Henderson     int bound;
1632fcf5ef2aSThomas Huth 
1633fcf5ef2aSThomas Huth     dc->cpu = cpu;
1634683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1635fcf5ef2aSThomas Huth     dc->cpustate_changed = 0;
1636fcf5ef2aSThomas Huth     dc->abort_at_next_insn = 0;
1637d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
163820800179SRichard Henderson     dc->r0 = NULL;
163920800179SRichard Henderson     dc->r0_set = false;
1640287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
1641b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1642b9c58aabSRichard Henderson     dc->jmp_dest = -1;
1643fcf5ef2aSThomas Huth 
1644372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1645372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1646fcf5ef2aSThomas Huth }
1647fcf5ef2aSThomas Huth 
1648372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1649fcf5ef2aSThomas Huth {
1650fcf5ef2aSThomas Huth }
1651fcf5ef2aSThomas Huth 
1652372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1653372122e3SRichard Henderson {
1654683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1655683a247eSRichard Henderson 
1656683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1657683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1658372122e3SRichard Henderson }
1659fcf5ef2aSThomas Huth 
1660372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1661372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1662372122e3SRichard Henderson {
1663372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1664372122e3SRichard Henderson 
1665372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1666372122e3SRichard Henderson 
1667372122e3SRichard Henderson     /*
1668372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1669372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1670372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1671372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1672372122e3SRichard Henderson      */
1673372122e3SRichard Henderson     dc->base.pc_next += 4;
1674372122e3SRichard Henderson     return true;
1675372122e3SRichard Henderson }
1676372122e3SRichard Henderson 
1677372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1678372122e3SRichard Henderson {
1679372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1680372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
168144d1432bSRichard Henderson     uint32_t ir;
1682372122e3SRichard Henderson 
1683372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1684372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1685372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1686372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1687fcf5ef2aSThomas Huth     }
1688fcf5ef2aSThomas Huth 
16896f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
16906f9642d7SRichard Henderson 
169144d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
169244d1432bSRichard Henderson     if (!decode(dc, ir)) {
169344d1432bSRichard Henderson         old_decode(dc, ir);
169444d1432bSRichard Henderson     }
169520800179SRichard Henderson 
169620800179SRichard Henderson     if (dc->r0) {
169720800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
169820800179SRichard Henderson         dc->r0 = NULL;
169920800179SRichard Henderson         dc->r0_set = false;
170020800179SRichard Henderson     }
170120800179SRichard Henderson 
17026f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
17036f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1704d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1705372122e3SRichard Henderson     }
17066f9642d7SRichard Henderson 
17071e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
17086f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1709d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1710fcf5ef2aSThomas Huth 
1711b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
1712372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
1713fcf5ef2aSThomas Huth             do_rti(dc);
1714b9c58aabSRichard Henderson         } else if (dc->tb_flags & DRTB_FLAG) {
1715fcf5ef2aSThomas Huth             do_rtb(dc);
1716b9c58aabSRichard Henderson         } else if (dc->tb_flags & DRTE_FLAG) {
1717fcf5ef2aSThomas Huth             do_rte(dc);
1718372122e3SRichard Henderson         }
1719372122e3SRichard Henderson         dc->base.is_jmp = DISAS_JUMP;
1720372122e3SRichard Henderson     }
1721372122e3SRichard Henderson 
1722372122e3SRichard Henderson     /* Force an exit if the per-tb cpu state has changed.  */
1723372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
1724372122e3SRichard Henderson         dc->base.is_jmp = DISAS_UPDATE;
1725372122e3SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1726372122e3SRichard Henderson     }
1727372122e3SRichard Henderson }
1728372122e3SRichard Henderson 
1729372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1730372122e3SRichard Henderson {
1731372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1732372122e3SRichard Henderson 
1733372122e3SRichard Henderson     assert(!dc->abort_at_next_insn);
1734372122e3SRichard Henderson 
1735372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1736372122e3SRichard Henderson         /* We have already exited the TB. */
1737372122e3SRichard Henderson         return;
1738372122e3SRichard Henderson     }
1739372122e3SRichard Henderson 
1740372122e3SRichard Henderson     t_sync_flags(dc);
1741372122e3SRichard Henderson 
1742372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1743372122e3SRichard Henderson     case DISAS_TOO_MANY:
1744372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1745372122e3SRichard Henderson         return;
1746372122e3SRichard Henderson 
1747372122e3SRichard Henderson     case DISAS_UPDATE:
1748372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1749372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1750372122e3SRichard Henderson         } else {
1751372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1752372122e3SRichard Henderson         }
1753372122e3SRichard Henderson         return;
1754372122e3SRichard Henderson 
1755372122e3SRichard Henderson     case DISAS_JUMP:
1756b9c58aabSRichard Henderson         if (dc->jmp_dest != -1 && !cs->singlestep_enabled) {
1757b9c58aabSRichard Henderson             /* Direct jump. */
1758b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1759b9c58aabSRichard Henderson 
1760b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1761b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1762b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1763b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1764b9c58aabSRichard Henderson 
1765b9c58aabSRichard Henderson                 /*
1766b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1767b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1768b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1769b9c58aabSRichard Henderson                  */
1770b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1771b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1772b9c58aabSRichard Henderson 
1773b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1774b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1775b9c58aabSRichard Henderson                 gen_set_label(taken);
1776b9c58aabSRichard Henderson             }
1777b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1778b9c58aabSRichard Henderson             return;
1779b9c58aabSRichard Henderson         }
1780b9c58aabSRichard Henderson 
1781b9c58aabSRichard Henderson         /* Indirect jump (or direct jump w/ singlestep) */
1782b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1783b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1784372122e3SRichard Henderson 
1785372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1786372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1787372122e3SRichard Henderson         } else {
1788372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1789372122e3SRichard Henderson         }
1790372122e3SRichard Henderson         return;
1791372122e3SRichard Henderson 
1792a2b80dbdSRichard Henderson     default:
1793a2b80dbdSRichard Henderson         g_assert_not_reached();
1794fcf5ef2aSThomas Huth     }
1795fcf5ef2aSThomas Huth }
1796fcf5ef2aSThomas Huth 
1797372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1798372122e3SRichard Henderson {
1799372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1800372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1801fcf5ef2aSThomas Huth }
1802372122e3SRichard Henderson 
1803372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1804372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1805372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1806372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1807372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1808372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1809372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1810372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1811372122e3SRichard Henderson };
1812372122e3SRichard Henderson 
1813372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1814372122e3SRichard Henderson {
1815372122e3SRichard Henderson     DisasContext dc;
1816372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1817fcf5ef2aSThomas Huth }
1818fcf5ef2aSThomas Huth 
181990c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1820fcf5ef2aSThomas Huth {
1821fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1822fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
18230c3da918SRichard Henderson     uint32_t iflags;
1824fcf5ef2aSThomas Huth     int i;
1825fcf5ef2aSThomas Huth 
18260c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18270c3da918SRichard Henderson                  env->pc, env->msr,
18282e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18292e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18302e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18312e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18320c3da918SRichard Henderson 
18330c3da918SRichard Henderson     iflags = env->iflags;
18340c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18350c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18360c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18372ead1b18SJoe Komlodi     }
18380c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18390c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18400c3da918SRichard Henderson     }
18410c3da918SRichard Henderson     if (iflags & D_FLAG) {
1842b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18430c3da918SRichard Henderson     }
18440c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18450c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18460c3da918SRichard Henderson     }
18470c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18480c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18490c3da918SRichard Henderson     }
18500c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18510c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18520c3da918SRichard Henderson     }
18530c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18540c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18552ead1b18SJoe Komlodi     }
1856fcf5ef2aSThomas Huth 
18570c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
18580c3da918SRichard Henderson                  "ear=0x%016" PRIx64 " slr=0x%x shr=0x%x\n",
18590c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18600c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18610c3da918SRichard Henderson 
18620c3da918SRichard Henderson     for (i = 0; i < 12; i++) {
18630c3da918SRichard Henderson         qemu_fprintf(f, "rpvr%-2d=%08x%c",
18640c3da918SRichard Henderson                      i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' ');
1865fcf5ef2aSThomas Huth     }
18660c3da918SRichard Henderson 
18670c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18680c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18690c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18700c3da918SRichard Henderson     }
18710c3da918SRichard Henderson     qemu_fprintf(f, "\n");
1872fcf5ef2aSThomas Huth }
1873fcf5ef2aSThomas Huth 
1874fcf5ef2aSThomas Huth void mb_tcg_init(void)
1875fcf5ef2aSThomas Huth {
1876480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1877480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1878fcf5ef2aSThomas Huth 
1879480d29a8SRichard Henderson     static const struct {
1880480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1881480d29a8SRichard Henderson     } i32s[] = {
1882480d29a8SRichard Henderson         R(0),  R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1883480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1884480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1885480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1886480d29a8SRichard Henderson 
1887480d29a8SRichard Henderson         SP(pc),
1888480d29a8SRichard Henderson         SP(msr),
18891074c0fbSRichard Henderson         SP(msr_c),
1890480d29a8SRichard Henderson         SP(imm),
1891480d29a8SRichard Henderson         SP(iflags),
1892b9c58aabSRichard Henderson         SP(bvalue),
1893480d29a8SRichard Henderson         SP(btarget),
1894480d29a8SRichard Henderson         SP(res_val),
1895480d29a8SRichard Henderson     };
1896480d29a8SRichard Henderson 
1897480d29a8SRichard Henderson #undef R
1898480d29a8SRichard Henderson #undef SP
1899480d29a8SRichard Henderson 
1900480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1901480d29a8SRichard Henderson         *i32s[i].var =
1902480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1903fcf5ef2aSThomas Huth     }
190476e8187dSRichard Henderson 
1905480d29a8SRichard Henderson     cpu_res_addr =
1906480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1907fcf5ef2aSThomas Huth }
1908fcf5ef2aSThomas Huth 
1909fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1910fcf5ef2aSThomas Huth                           target_ulong *data)
1911fcf5ef2aSThomas Huth {
191276e8187dSRichard Henderson     env->pc = data[0];
1913683a247eSRichard Henderson     env->iflags = data[1];
1914fcf5ef2aSThomas Huth }
1915