xref: /openbmc/qemu/target/microblaze/translate.c (revision 3d35bcc2135faefa7565f1023ce3e7df9032aedc)
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 "exec/cpu_ldst.h"
28fcf5ef2aSThomas Huth #include "exec/helper-gen.h"
2977fc6f5eSLluís Vilanova #include "exec/translator.h"
3090c84c56SMarkus Armbruster #include "qemu/qemu-print.h"
31fcf5ef2aSThomas Huth 
32fcf5ef2aSThomas Huth #include "trace-tcg.h"
33fcf5ef2aSThomas Huth #include "exec/log.h"
34fcf5ef2aSThomas Huth 
35fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
36fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
37fcf5ef2aSThomas Huth 
3877fc6f5eSLluís Vilanova /* is_jmp field values */
3977fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
4017e77796SRichard Henderson #define DISAS_EXIT    DISAS_TARGET_1 /* all cpu state modified dynamically */
4177fc6f5eSLluís Vilanova 
42f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */
43f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2
44f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */
45f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3
46f6278ca9SRichard Henderson 
47cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
480f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
493e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
501074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
519b158558SRichard Henderson static TCGv_i32 cpu_imm;
52b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
530f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
549b158558SRichard Henderson static TCGv_i32 cpu_iflags;
559b158558SRichard Henderson static TCGv cpu_res_addr;
569b158558SRichard Henderson static TCGv_i32 cpu_res_val;
57fcf5ef2aSThomas Huth 
58fcf5ef2aSThomas Huth #include "exec/gen-icount.h"
59fcf5ef2aSThomas Huth 
60fcf5ef2aSThomas Huth /* This is the state at translation time.  */
61fcf5ef2aSThomas Huth typedef struct DisasContext {
62d4705ae0SRichard Henderson     DisasContextBase base;
63fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu;
64fcf5ef2aSThomas Huth 
65683a247eSRichard Henderson     /* TCG op of the current insn_start.  */
66683a247eSRichard Henderson     TCGOp *insn_start;
67683a247eSRichard Henderson 
6820800179SRichard Henderson     TCGv_i32 r0;
6920800179SRichard Henderson     bool r0_set;
7020800179SRichard Henderson 
71fcf5ef2aSThomas Huth     /* Decoder.  */
72d7ecb757SRichard Henderson     uint32_t ext_imm;
73683a247eSRichard Henderson     unsigned int tb_flags;
746f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
75287b1defSRichard Henderson     int mem_index;
76fcf5ef2aSThomas Huth 
77b9c58aabSRichard Henderson     /* Condition under which to jump, including NEVER and ALWAYS. */
78b9c58aabSRichard Henderson     TCGCond jmp_cond;
79b9c58aabSRichard Henderson 
80b9c58aabSRichard Henderson     /* Immediate branch-taken destination, or -1 for indirect. */
81b9c58aabSRichard Henderson     uint32_t jmp_dest;
82fcf5ef2aSThomas Huth } DisasContext;
83fcf5ef2aSThomas Huth 
8420800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8520800179SRichard Henderson {
8620800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
8720800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
8820800179SRichard Henderson     }
8920800179SRichard Henderson     return x;
9020800179SRichard Henderson }
9120800179SRichard Henderson 
9244d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9344d1432bSRichard Henderson #include "decode-insns.c.inc"
9444d1432bSRichard Henderson 
95683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
96fcf5ef2aSThomas Huth {
97fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
9888e74b61SRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
9988e74b61SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
100fcf5ef2aSThomas Huth     }
101fcf5ef2aSThomas Huth }
102fcf5ef2aSThomas Huth 
10341ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
104fcf5ef2aSThomas Huth {
105fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
106fcf5ef2aSThomas Huth 
107fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
108fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
109d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
110fcf5ef2aSThomas Huth }
111fcf5ef2aSThomas Huth 
11241ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
11341ba37c4SRichard Henderson {
11441ba37c4SRichard Henderson     t_sync_flags(dc);
115d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
11641ba37c4SRichard Henderson     gen_raise_exception(dc, index);
11741ba37c4SRichard Henderson }
11841ba37c4SRichard Henderson 
11941ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
12041ba37c4SRichard Henderson {
12141ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
12241ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
12341ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
12441ba37c4SRichard Henderson 
12541ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
12641ba37c4SRichard Henderson }
12741ba37c4SRichard Henderson 
128fcf5ef2aSThomas Huth static inline bool use_goto_tb(DisasContext *dc, target_ulong dest)
129fcf5ef2aSThomas Huth {
130fcf5ef2aSThomas Huth #ifndef CONFIG_USER_ONLY
131d4705ae0SRichard Henderson     return (dc->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
132fcf5ef2aSThomas Huth #else
133fcf5ef2aSThomas Huth     return true;
134fcf5ef2aSThomas Huth #endif
135fcf5ef2aSThomas Huth }
136fcf5ef2aSThomas Huth 
137fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
138fcf5ef2aSThomas Huth {
139d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1400b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1410b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1420b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1430b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
1440b46fa08SRichard Henderson     } else if (use_goto_tb(dc, dest)) {
145fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1460f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
147d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
148fcf5ef2aSThomas Huth     } else {
1490f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
15007ea28b4SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
151fcf5ef2aSThomas Huth     }
152d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
153fcf5ef2aSThomas Huth }
154fcf5ef2aSThomas Huth 
155bdfc1e88SEdgar E. Iglesias /*
1569ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1579ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1589ba8cd45SEdgar E. Iglesias  */
1599ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1609ba8cd45SEdgar E. Iglesias {
1612c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1625143fdf3SEdgar E. Iglesias         && dc->cpu->cfg.illegal_opcode_exception) {
16341ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1649ba8cd45SEdgar E. Iglesias     }
1659ba8cd45SEdgar E. Iglesias     return cond;
1669ba8cd45SEdgar E. Iglesias }
1679ba8cd45SEdgar E. Iglesias 
1689ba8cd45SEdgar E. Iglesias /*
169bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
170bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
171bdfc1e88SEdgar E. Iglesias  */
172bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
173bdfc1e88SEdgar E. Iglesias {
174287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
175bdfc1e88SEdgar E. Iglesias 
1762c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
17741ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
178bdfc1e88SEdgar E. Iglesias     }
179bdfc1e88SEdgar E. Iglesias     return cond_user;
180bdfc1e88SEdgar E. Iglesias }
181bdfc1e88SEdgar E. Iglesias 
18220800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
183fcf5ef2aSThomas Huth {
18420800179SRichard Henderson     if (likely(reg != 0)) {
18520800179SRichard Henderson         return cpu_R[reg];
186fcf5ef2aSThomas Huth     }
18720800179SRichard Henderson     if (!dc->r0_set) {
18820800179SRichard Henderson         if (dc->r0 == NULL) {
18920800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
190fcf5ef2aSThomas Huth         }
19120800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
19220800179SRichard Henderson         dc->r0_set = true;
19320800179SRichard Henderson     }
19420800179SRichard Henderson     return dc->r0;
195fcf5ef2aSThomas Huth }
196fcf5ef2aSThomas Huth 
19720800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
19820800179SRichard Henderson {
19920800179SRichard Henderson     if (likely(reg != 0)) {
20020800179SRichard Henderson         return cpu_R[reg];
20120800179SRichard Henderson     }
20220800179SRichard Henderson     if (dc->r0 == NULL) {
20320800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
20420800179SRichard Henderson     }
20520800179SRichard Henderson     return dc->r0;
206fcf5ef2aSThomas Huth }
207fcf5ef2aSThomas Huth 
20820800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
20920800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
21020800179SRichard Henderson {
21120800179SRichard Henderson     TCGv_i32 rd, ra, rb;
21220800179SRichard Henderson 
21320800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
21420800179SRichard Henderson         return true;
215fcf5ef2aSThomas Huth     }
21620800179SRichard Henderson 
21720800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
21820800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
21920800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
22020800179SRichard Henderson     fn(rd, ra, rb);
22120800179SRichard Henderson     return true;
22220800179SRichard Henderson }
22320800179SRichard Henderson 
22439cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
22539cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
22639cf3864SRichard Henderson {
22739cf3864SRichard Henderson     TCGv_i32 rd, ra;
22839cf3864SRichard Henderson 
22939cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
23039cf3864SRichard Henderson         return true;
23139cf3864SRichard Henderson     }
23239cf3864SRichard Henderson 
23339cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
23439cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
23539cf3864SRichard Henderson     fn(rd, ra);
23639cf3864SRichard Henderson     return true;
23739cf3864SRichard Henderson }
23839cf3864SRichard Henderson 
23920800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
24020800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
24120800179SRichard Henderson {
24220800179SRichard Henderson     TCGv_i32 rd, ra;
24320800179SRichard Henderson 
24420800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
24520800179SRichard Henderson         return true;
24620800179SRichard Henderson     }
24720800179SRichard Henderson 
24820800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
24920800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
25020800179SRichard Henderson     fni(rd, ra, arg->imm);
25120800179SRichard Henderson     return true;
25220800179SRichard Henderson }
25320800179SRichard Henderson 
25420800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
25520800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
25620800179SRichard Henderson {
25720800179SRichard Henderson     TCGv_i32 rd, ra, imm;
25820800179SRichard Henderson 
25920800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
26020800179SRichard Henderson         return true;
26120800179SRichard Henderson     }
26220800179SRichard Henderson 
26320800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26420800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
26520800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
26620800179SRichard Henderson 
26720800179SRichard Henderson     fn(rd, ra, imm);
26820800179SRichard Henderson 
26920800179SRichard Henderson     tcg_temp_free_i32(imm);
27020800179SRichard Henderson     return true;
27120800179SRichard Henderson }
27220800179SRichard Henderson 
27320800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
27420800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
27520800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
27620800179SRichard Henderson 
277607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
278607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
279607f5767SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); }
280607f5767SRichard Henderson 
28139cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
28239cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
28339cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
28439cf3864SRichard Henderson 
28539cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
28639cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
28739cf3864SRichard Henderson     { return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); }
28839cf3864SRichard Henderson 
28920800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
29020800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29120800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
29220800179SRichard Henderson 
29397955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
29497955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29597955cebSRichard Henderson     { return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); }
29697955cebSRichard Henderson 
29720800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
29820800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29920800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
30020800179SRichard Henderson 
301d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
302d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
303d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
304d5aead3dSRichard Henderson 
305d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
306d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
307d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
308d5aead3dSRichard Henderson 
30920800179SRichard Henderson /* No input carry, but output carry. */
31020800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
31120800179SRichard Henderson {
31220800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
31320800179SRichard Henderson 
31420800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
31520800179SRichard Henderson 
31620800179SRichard Henderson     tcg_temp_free_i32(zero);
31720800179SRichard Henderson }
31820800179SRichard Henderson 
31920800179SRichard Henderson /* Input and output carry. */
32020800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
32120800179SRichard Henderson {
32220800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
32320800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
32420800179SRichard Henderson 
32520800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
32620800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
32720800179SRichard Henderson 
32820800179SRichard Henderson     tcg_temp_free_i32(tmp);
32920800179SRichard Henderson     tcg_temp_free_i32(zero);
33020800179SRichard Henderson }
33120800179SRichard Henderson 
33220800179SRichard Henderson /* Input carry, but no output carry. */
33320800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
33420800179SRichard Henderson {
33520800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
33620800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
33720800179SRichard Henderson }
33820800179SRichard Henderson 
33920800179SRichard Henderson DO_TYPEA(add, true, gen_add)
34020800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
34120800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
34220800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
34320800179SRichard Henderson 
34420800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
34520800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
34620800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
34720800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
34820800179SRichard Henderson 
349cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
350cb0a0a4cSRichard Henderson {
351cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
352cb0a0a4cSRichard Henderson }
353cb0a0a4cSRichard Henderson 
354cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
355cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
356cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
357cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
358cb0a0a4cSRichard Henderson 
359081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
360081d8e02SRichard Henderson {
361081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
362081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
363081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
364081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
365081d8e02SRichard Henderson }
366081d8e02SRichard Henderson 
367081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
368081d8e02SRichard Henderson {
369081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
370081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
371081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
372081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
373081d8e02SRichard Henderson }
374081d8e02SRichard Henderson 
375081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
376081d8e02SRichard Henderson {
377081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
378081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
379081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
380081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
381081d8e02SRichard Henderson }
382081d8e02SRichard Henderson 
383081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
384081d8e02SRichard Henderson {
385081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
386081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
387081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
388081d8e02SRichard Henderson 
389081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
390081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
391081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
392081d8e02SRichard Henderson                       imm_w, imm_s);
393081d8e02SRichard Henderson     } else {
394081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
395081d8e02SRichard Henderson     }
396081d8e02SRichard Henderson }
397081d8e02SRichard Henderson 
398081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
399081d8e02SRichard Henderson {
400081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
401081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
402081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
403081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
404081d8e02SRichard Henderson 
405081d8e02SRichard Henderson     if (imm_w < imm_s) {
406081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
407081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
408081d8e02SRichard Henderson                       imm_w, imm_s);
409081d8e02SRichard Henderson     } else {
410081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
411081d8e02SRichard Henderson     }
412081d8e02SRichard Henderson }
413081d8e02SRichard Henderson 
414081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
415081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
416081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
417081d8e02SRichard Henderson 
418081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
419081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
420081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
421081d8e02SRichard Henderson 
422081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
423081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
424081d8e02SRichard Henderson 
42539cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
42639cf3864SRichard Henderson {
42739cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
42839cf3864SRichard Henderson }
42939cf3864SRichard Henderson 
43039cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
43139cf3864SRichard Henderson 
43258b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
43358b48b63SRichard Henderson {
43458b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
43558b48b63SRichard Henderson 
43658b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
43758b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
43858b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
43958b48b63SRichard Henderson     tcg_temp_free_i32(lt);
44058b48b63SRichard Henderson }
44158b48b63SRichard Henderson 
44258b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
44358b48b63SRichard Henderson {
44458b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
44558b48b63SRichard Henderson 
44658b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
44758b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
44858b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
44958b48b63SRichard Henderson     tcg_temp_free_i32(lt);
45058b48b63SRichard Henderson }
45158b48b63SRichard Henderson 
45258b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
45358b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
454a2b0b90eSRichard Henderson 
455d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
456d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
457d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
458d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
459d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
460d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
461d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
462d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
463d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
464d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
465d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
466d5aead3dSRichard Henderson 
467d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
468d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
469d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
470d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
471d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
472d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
473d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
474d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
475d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
476d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
477d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
478d5aead3dSRichard Henderson 
479d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
480d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
481d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
482d5aead3dSRichard Henderson 
483d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
484d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
485d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
486d5aead3dSRichard Henderson 
487d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
488b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
489b1354342SRichard Henderson {
490b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
491b1354342SRichard Henderson }
492b1354342SRichard Henderson 
493b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
494b1354342SRichard Henderson {
495b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
496b1354342SRichard Henderson }
497b1354342SRichard Henderson 
498b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
499b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
500b1354342SRichard Henderson 
501e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
502e64b2e5cSRichard Henderson {
503e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
504e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
5056f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
506e64b2e5cSRichard Henderson     return true;
507e64b2e5cSRichard Henderson }
508e64b2e5cSRichard Henderson 
50997955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
51097955cebSRichard Henderson {
51197955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
51297955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
51397955cebSRichard Henderson     tcg_temp_free_i32(tmp);
51497955cebSRichard Henderson }
51597955cebSRichard Henderson 
51697955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
51797955cebSRichard Henderson {
51897955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
51997955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
52097955cebSRichard Henderson     tcg_temp_free_i32(tmp);
52197955cebSRichard Henderson }
52297955cebSRichard Henderson 
52397955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
52497955cebSRichard Henderson {
52597955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
52697955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
52797955cebSRichard Henderson     tcg_temp_free_i32(tmp);
52897955cebSRichard Henderson }
52997955cebSRichard Henderson 
53097955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
53197955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
53297955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
53397955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
53497955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
53597955cebSRichard Henderson 
536cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
537cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
538cb0a0a4cSRichard Henderson 
539607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
540607f5767SRichard Henderson {
541607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
542607f5767SRichard Henderson }
543607f5767SRichard Henderson 
544607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
545607f5767SRichard Henderson {
546607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
547607f5767SRichard Henderson }
548607f5767SRichard Henderson 
549607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
550607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
551607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
552607f5767SRichard Henderson 
553a2b0b90eSRichard Henderson /* No input carry, but output carry. */
554a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
555a2b0b90eSRichard Henderson {
556a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
557a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
558a2b0b90eSRichard Henderson }
559a2b0b90eSRichard Henderson 
560a2b0b90eSRichard Henderson /* Input and output carry. */
561a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
562a2b0b90eSRichard Henderson {
563a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
564a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
565a2b0b90eSRichard Henderson 
566a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
567a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
568a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
569a2b0b90eSRichard Henderson 
570a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
571a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
572a2b0b90eSRichard Henderson }
573a2b0b90eSRichard Henderson 
574a2b0b90eSRichard Henderson /* No input or output carry. */
575a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
576a2b0b90eSRichard Henderson {
577a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
578a2b0b90eSRichard Henderson }
579a2b0b90eSRichard Henderson 
580a2b0b90eSRichard Henderson /* Input carry, no output carry. */
581a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
582a2b0b90eSRichard Henderson {
583a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
584a2b0b90eSRichard Henderson 
585a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
586a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
587a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
588a2b0b90eSRichard Henderson 
589a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
590a2b0b90eSRichard Henderson }
591a2b0b90eSRichard Henderson 
592a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
593a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
594a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
595a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
596a2b0b90eSRichard Henderson 
597a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
598a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
599a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
600a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
601a2b0b90eSRichard Henderson 
60239cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
60339cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
60439cf3864SRichard Henderson 
60539cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
60639cf3864SRichard Henderson {
60739cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
60839cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
60939cf3864SRichard Henderson }
61039cf3864SRichard Henderson 
61139cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
61239cf3864SRichard Henderson {
61339cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
61439cf3864SRichard Henderson 
61539cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
61639cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
61739cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
61839cf3864SRichard Henderson 
61939cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
62039cf3864SRichard Henderson }
62139cf3864SRichard Henderson 
62239cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
62339cf3864SRichard Henderson {
62439cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
62539cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
62639cf3864SRichard Henderson }
62739cf3864SRichard Henderson 
62839cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
62939cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
63039cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
63139cf3864SRichard Henderson 
63239cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
63339cf3864SRichard Henderson {
63439cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
63539cf3864SRichard Henderson }
63639cf3864SRichard Henderson 
63739cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
63839cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
63939cf3864SRichard Henderson 
64039cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
64139cf3864SRichard Henderson {
64239cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
64339cf3864SRichard Henderson     trap_userspace(dc, true);
64439cf3864SRichard Henderson     return true;
64539cf3864SRichard Henderson }
64639cf3864SRichard Henderson 
647cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
648cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
649cb0a0a4cSRichard Henderson 
650d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
651d8e59c4aSRichard Henderson {
652d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
653d8e59c4aSRichard Henderson 
654d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
655d8e59c4aSRichard Henderson     if (ra && rb) {
656d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
657d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
658d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
659d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
660d8e59c4aSRichard Henderson     } else if (ra) {
661d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
662d8e59c4aSRichard Henderson     } else if (rb) {
663d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
664d8e59c4aSRichard Henderson     } else {
665d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
666d8e59c4aSRichard Henderson     }
667d8e59c4aSRichard Henderson 
668d8e59c4aSRichard Henderson     if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) {
669d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
670d8e59c4aSRichard Henderson     }
671d8e59c4aSRichard Henderson     return ret;
672d8e59c4aSRichard Henderson }
673d8e59c4aSRichard Henderson 
674d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
675d8e59c4aSRichard Henderson {
676d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
677d8e59c4aSRichard Henderson 
678d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
679d8e59c4aSRichard Henderson     if (ra) {
680d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
681d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
682d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
683d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
684d8e59c4aSRichard Henderson     } else {
685d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
686d8e59c4aSRichard Henderson     }
687d8e59c4aSRichard Henderson 
688d8e59c4aSRichard Henderson     if (ra == 1 && dc->cpu->cfg.stackprot) {
689d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
690d8e59c4aSRichard Henderson     }
691d8e59c4aSRichard Henderson     return ret;
692d8e59c4aSRichard Henderson }
693d8e59c4aSRichard Henderson 
69419f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
695d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
696d8e59c4aSRichard Henderson {
697d8e59c4aSRichard Henderson     int addr_size = dc->cpu->cfg.addr_size;
698d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
699d8e59c4aSRichard Henderson 
700d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
701d8e59c4aSRichard Henderson         if (rb) {
702d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
703d8e59c4aSRichard Henderson         } else {
704d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
705d8e59c4aSRichard Henderson         }
706d8e59c4aSRichard Henderson     } else {
707d8e59c4aSRichard Henderson         if (rb) {
708d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
709d8e59c4aSRichard Henderson         } else {
710d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
711d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
712d8e59c4aSRichard Henderson         }
713d8e59c4aSRichard Henderson         if (addr_size < 64) {
714d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
715d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
716d8e59c4aSRichard Henderson         }
717d8e59c4aSRichard Henderson     }
718d8e59c4aSRichard Henderson     return ret;
719d8e59c4aSRichard Henderson }
72019f27b6cSRichard Henderson #endif
721d8e59c4aSRichard Henderson 
722ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
723ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
724ab0c8d0fSRichard Henderson {
725ab0c8d0fSRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
726ab0c8d0fSRichard Henderson 
727ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
728ab0c8d0fSRichard Henderson     iflags |= rd << 5;
729ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
730ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
731ab0c8d0fSRichard Henderson 
732ab0c8d0fSRichard Henderson     tcg_set_insn_start_param(dc->insn_start, 1, iflags);
733ab0c8d0fSRichard Henderson }
734ab0c8d0fSRichard Henderson 
735d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
736d8e59c4aSRichard Henderson                     int mem_index, bool rev)
737d8e59c4aSRichard Henderson {
738d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
739d8e59c4aSRichard Henderson 
740d8e59c4aSRichard Henderson     /*
741d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
742d8e59c4aSRichard Henderson      *
743d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
744d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
745d8e59c4aSRichard Henderson      */
746d8e59c4aSRichard Henderson     if (rev) {
747d8e59c4aSRichard Henderson         if (size > MO_8) {
748d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
749d8e59c4aSRichard Henderson         }
750d8e59c4aSRichard Henderson         if (size < MO_32) {
751d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
752d8e59c4aSRichard Henderson         }
753d8e59c4aSRichard Henderson     }
754d8e59c4aSRichard Henderson 
755ab0c8d0fSRichard Henderson     if (size > MO_8 &&
756ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
757ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
758ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
759ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
760d8e59c4aSRichard Henderson     }
761d8e59c4aSRichard Henderson 
762ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
763d8e59c4aSRichard Henderson 
764d8e59c4aSRichard Henderson     tcg_temp_free(addr);
765d8e59c4aSRichard Henderson     return true;
766d8e59c4aSRichard Henderson }
767d8e59c4aSRichard Henderson 
768d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
769d8e59c4aSRichard Henderson {
770d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
771d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
772d8e59c4aSRichard Henderson }
773d8e59c4aSRichard Henderson 
774d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
775d8e59c4aSRichard Henderson {
776d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
777d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
778d8e59c4aSRichard Henderson }
779d8e59c4aSRichard Henderson 
780d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
781d8e59c4aSRichard Henderson {
782d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
783d8e59c4aSRichard Henderson         return true;
784d8e59c4aSRichard Henderson     }
78519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
78619f27b6cSRichard Henderson     return true;
78719f27b6cSRichard Henderson #else
788d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
789d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
79019f27b6cSRichard Henderson #endif
791d8e59c4aSRichard Henderson }
792d8e59c4aSRichard Henderson 
793d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
794d8e59c4aSRichard Henderson {
795d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
796d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
797d8e59c4aSRichard Henderson }
798d8e59c4aSRichard Henderson 
799d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
800d8e59c4aSRichard Henderson {
801d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
802d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
803d8e59c4aSRichard Henderson }
804d8e59c4aSRichard Henderson 
805d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
806d8e59c4aSRichard Henderson {
807d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
808d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
809d8e59c4aSRichard Henderson }
810d8e59c4aSRichard Henderson 
811d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
812d8e59c4aSRichard Henderson {
813d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
814d8e59c4aSRichard Henderson         return true;
815d8e59c4aSRichard Henderson     }
81619f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
81719f27b6cSRichard Henderson     return true;
81819f27b6cSRichard Henderson #else
819d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
820d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
82119f27b6cSRichard Henderson #endif
822d8e59c4aSRichard Henderson }
823d8e59c4aSRichard Henderson 
824d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
825d8e59c4aSRichard Henderson {
826d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
827d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
828d8e59c4aSRichard Henderson }
829d8e59c4aSRichard Henderson 
830d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
831d8e59c4aSRichard Henderson {
832d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
833d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
834d8e59c4aSRichard Henderson }
835d8e59c4aSRichard Henderson 
836d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
837d8e59c4aSRichard Henderson {
838d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
839d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
840d8e59c4aSRichard Henderson }
841d8e59c4aSRichard Henderson 
842d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
843d8e59c4aSRichard Henderson {
844d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
845d8e59c4aSRichard Henderson         return true;
846d8e59c4aSRichard Henderson     }
84719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
84819f27b6cSRichard Henderson     return true;
84919f27b6cSRichard Henderson #else
850d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
851d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
85219f27b6cSRichard Henderson #endif
853d8e59c4aSRichard Henderson }
854d8e59c4aSRichard Henderson 
855d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
856d8e59c4aSRichard Henderson {
857d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
858d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
859d8e59c4aSRichard Henderson }
860d8e59c4aSRichard Henderson 
861d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
862d8e59c4aSRichard Henderson {
863d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
864d8e59c4aSRichard Henderson 
865d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
866d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
867d8e59c4aSRichard Henderson 
868d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
869d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
870d8e59c4aSRichard Henderson     tcg_temp_free(addr);
871d8e59c4aSRichard Henderson 
872d8e59c4aSRichard Henderson     if (arg->rd) {
873d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
874d8e59c4aSRichard Henderson     }
875d8e59c4aSRichard Henderson 
876d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
877d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
878d8e59c4aSRichard Henderson     return true;
879d8e59c4aSRichard Henderson }
880d8e59c4aSRichard Henderson 
881d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
882d8e59c4aSRichard Henderson                      int mem_index, bool rev)
883d8e59c4aSRichard Henderson {
884d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
885d8e59c4aSRichard Henderson 
886d8e59c4aSRichard Henderson     /*
887d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
888d8e59c4aSRichard Henderson      *
889d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
890d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
891d8e59c4aSRichard Henderson      */
892d8e59c4aSRichard Henderson     if (rev) {
893d8e59c4aSRichard Henderson         if (size > MO_8) {
894d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
895d8e59c4aSRichard Henderson         }
896d8e59c4aSRichard Henderson         if (size < MO_32) {
897d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
898d8e59c4aSRichard Henderson         }
899d8e59c4aSRichard Henderson     }
900d8e59c4aSRichard Henderson 
901ab0c8d0fSRichard Henderson     if (size > MO_8 &&
902ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
903ab0c8d0fSRichard Henderson         dc->cpu->cfg.unaligned_exceptions) {
904ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
905ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
906d8e59c4aSRichard Henderson     }
907d8e59c4aSRichard Henderson 
908ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
909ab0c8d0fSRichard Henderson 
910d8e59c4aSRichard Henderson     tcg_temp_free(addr);
911d8e59c4aSRichard Henderson     return true;
912d8e59c4aSRichard Henderson }
913d8e59c4aSRichard Henderson 
914d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
915d8e59c4aSRichard Henderson {
916d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
917d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
918d8e59c4aSRichard Henderson }
919d8e59c4aSRichard Henderson 
920d8e59c4aSRichard Henderson static bool trans_sbr(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, true);
924d8e59c4aSRichard Henderson }
925d8e59c4aSRichard Henderson 
926d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
927d8e59c4aSRichard Henderson {
928d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
929d8e59c4aSRichard Henderson         return true;
930d8e59c4aSRichard Henderson     }
93119f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
93219f27b6cSRichard Henderson     return true;
93319f27b6cSRichard Henderson #else
934d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
935d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
93619f27b6cSRichard Henderson #endif
937d8e59c4aSRichard Henderson }
938d8e59c4aSRichard Henderson 
939d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
940d8e59c4aSRichard Henderson {
941d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
942d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
943d8e59c4aSRichard Henderson }
944d8e59c4aSRichard Henderson 
945d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
946d8e59c4aSRichard Henderson {
947d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
948d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
949d8e59c4aSRichard Henderson }
950d8e59c4aSRichard Henderson 
951d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
952d8e59c4aSRichard Henderson {
953d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
954d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
955d8e59c4aSRichard Henderson }
956d8e59c4aSRichard Henderson 
957d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
958d8e59c4aSRichard Henderson {
959d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
960d8e59c4aSRichard Henderson         return true;
961d8e59c4aSRichard Henderson     }
96219f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
96319f27b6cSRichard Henderson     return true;
96419f27b6cSRichard Henderson #else
965d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
966d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
96719f27b6cSRichard Henderson #endif
968d8e59c4aSRichard Henderson }
969d8e59c4aSRichard Henderson 
970d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
971d8e59c4aSRichard Henderson {
972d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
973d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
974d8e59c4aSRichard Henderson }
975d8e59c4aSRichard Henderson 
976d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
977d8e59c4aSRichard Henderson {
978d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
979d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
980d8e59c4aSRichard Henderson }
981d8e59c4aSRichard Henderson 
982d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
983d8e59c4aSRichard Henderson {
984d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
985d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
986d8e59c4aSRichard Henderson }
987d8e59c4aSRichard Henderson 
988d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
989d8e59c4aSRichard Henderson {
990d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
991d8e59c4aSRichard Henderson         return true;
992d8e59c4aSRichard Henderson     }
99319f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
99419f27b6cSRichard Henderson     return true;
99519f27b6cSRichard Henderson #else
996d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
997d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
99819f27b6cSRichard Henderson #endif
999d8e59c4aSRichard Henderson }
1000d8e59c4aSRichard Henderson 
1001d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1002d8e59c4aSRichard Henderson {
1003d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1004d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1005d8e59c4aSRichard Henderson }
1006d8e59c4aSRichard Henderson 
1007d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1008d8e59c4aSRichard Henderson {
1009d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1010d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1011d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1012d8e59c4aSRichard Henderson     TCGv_i32 tval;
1013d8e59c4aSRichard Henderson 
1014d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1015d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1016d8e59c4aSRichard Henderson 
1017d8e59c4aSRichard Henderson     /*
1018d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1019d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1020d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1021d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1022d8e59c4aSRichard Henderson      */
1023d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1024d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1025d8e59c4aSRichard Henderson 
1026d8e59c4aSRichard Henderson     /*
1027d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1028d8e59c4aSRichard Henderson      * the reserved location.
1029d8e59c4aSRichard Henderson      */
1030d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1031d8e59c4aSRichard Henderson 
1032d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1033d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1034d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1035d8e59c4aSRichard Henderson 
1036d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1037d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1038d8e59c4aSRichard Henderson 
1039d8e59c4aSRichard Henderson     /* Success */
1040d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1041d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1042d8e59c4aSRichard Henderson 
1043d8e59c4aSRichard Henderson     /* Failure */
1044d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1045d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1046d8e59c4aSRichard Henderson 
1047d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1048d8e59c4aSRichard Henderson 
1049d8e59c4aSRichard Henderson     /*
1050d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1051d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1052d8e59c4aSRichard Henderson      */
1053d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1054d8e59c4aSRichard Henderson     return true;
1055d8e59c4aSRichard Henderson }
1056d8e59c4aSRichard Henderson 
105716bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
105816bbbbc9SRichard Henderson {
105916bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
106016bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
106116bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
106216bbbbc9SRichard Henderson     }
106316bbbbc9SRichard Henderson }
106416bbbbc9SRichard Henderson 
106516bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
106616bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
106716bbbbc9SRichard Henderson {
106816bbbbc9SRichard Henderson     uint32_t add_pc;
106916bbbbc9SRichard Henderson 
107016bbbbc9SRichard Henderson     if (delay) {
107116bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
107216bbbbc9SRichard Henderson     }
107316bbbbc9SRichard Henderson 
107416bbbbc9SRichard Henderson     if (link) {
107516bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
107616bbbbc9SRichard Henderson     }
107716bbbbc9SRichard Henderson 
107816bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
107916bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
108016bbbbc9SRichard Henderson     if (dest_rb > 0) {
108116bbbbc9SRichard Henderson         dc->jmp_dest = -1;
108216bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
108316bbbbc9SRichard Henderson     } else {
108416bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
108516bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
108616bbbbc9SRichard Henderson     }
108716bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
108816bbbbc9SRichard Henderson     return true;
108916bbbbc9SRichard Henderson }
109016bbbbc9SRichard Henderson 
109116bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
109216bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
109316bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
109416bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
109516bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
109616bbbbc9SRichard Henderson 
109716bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
109816bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
109916bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
110016bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
110116bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
110216bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
110316bbbbc9SRichard Henderson 
1104fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1105fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1106fd779113SRichard Henderson {
1107fd779113SRichard Henderson     TCGv_i32 zero, next;
1108fd779113SRichard Henderson 
1109fd779113SRichard Henderson     if (delay) {
1110fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1111fd779113SRichard Henderson     }
1112fd779113SRichard Henderson 
1113fd779113SRichard Henderson     dc->jmp_cond = cond;
1114fd779113SRichard Henderson 
1115fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1116fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1117fd779113SRichard Henderson 
1118fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1119fd779113SRichard Henderson     if (dest_rb > 0) {
1120fd779113SRichard Henderson         dc->jmp_dest = -1;
1121fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1122fd779113SRichard Henderson     } else {
1123fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1124fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1125fd779113SRichard Henderson     }
1126fd779113SRichard Henderson 
1127fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1128fd779113SRichard Henderson     zero = tcg_const_i32(0);
1129fd779113SRichard Henderson     next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4);
1130fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1131fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1132fd779113SRichard Henderson                         cpu_btarget, next);
1133fd779113SRichard Henderson     tcg_temp_free_i32(zero);
1134fd779113SRichard Henderson     tcg_temp_free_i32(next);
1135fd779113SRichard Henderson 
1136fd779113SRichard Henderson     return true;
1137fd779113SRichard Henderson }
1138fd779113SRichard Henderson 
1139fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1140fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1141fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1142fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1143fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1144fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1145fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1146fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1147fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1148fd779113SRichard Henderson 
1149fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1150fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1151fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1152fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1153fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1154fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1155fd779113SRichard Henderson 
1156f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1157f5235314SRichard Henderson {
1158f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1159f5235314SRichard Henderson         return true;
1160f5235314SRichard Henderson     }
1161f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1162f5235314SRichard Henderson     if (arg->rd) {
1163f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1164f5235314SRichard Henderson     }
1165f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1166f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1167f5235314SRichard Henderson 
116817e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1169f5235314SRichard Henderson     return true;
1170f5235314SRichard Henderson }
1171f5235314SRichard Henderson 
1172f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1173f5235314SRichard Henderson {
1174f5235314SRichard Henderson     uint32_t imm = arg->imm;
1175f5235314SRichard Henderson 
1176f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1177f5235314SRichard Henderson         return true;
1178f5235314SRichard Henderson     }
1179f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1180f5235314SRichard Henderson     if (arg->rd) {
1181f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1182f5235314SRichard Henderson     }
1183f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1184f5235314SRichard Henderson 
1185f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1186f5235314SRichard Henderson     switch (imm) {
1187f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1188f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1189f5235314SRichard Henderson         break;
1190f5235314SRichard Henderson     case 0x18: /* debug trap */
1191f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1192f5235314SRichard Henderson         break;
1193f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1194f5235314SRichard Henderson         g_assert_not_reached();
1195f5235314SRichard Henderson     }
1196f5235314SRichard Henderson #else
1197f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1198f5235314SRichard Henderson 
1199f5235314SRichard Henderson     if (imm != 0x18) {
1200f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1201f5235314SRichard Henderson     }
1202f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1203f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1204f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1205f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1206f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1207f5235314SRichard Henderson     }
1208f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
120917e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1210f5235314SRichard Henderson #endif
1211f5235314SRichard Henderson 
1212f5235314SRichard Henderson     return true;
1213f5235314SRichard Henderson }
1214f5235314SRichard Henderson 
1215ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1216ee8c7f9fSRichard Henderson {
1217ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1218ee8c7f9fSRichard Henderson 
1219ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1220ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1221ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1222ee8c7f9fSRichard Henderson     }
1223ee8c7f9fSRichard Henderson 
1224ee8c7f9fSRichard Henderson     /* Sleep. */
1225ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1226ee8c7f9fSRichard Henderson         TCGv_i32 tmp_1;
1227ee8c7f9fSRichard Henderson 
1228ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1229ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1230ee8c7f9fSRichard Henderson             return true;
1231ee8c7f9fSRichard Henderson         }
1232ee8c7f9fSRichard Henderson 
1233ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1234ee8c7f9fSRichard Henderson 
1235ee8c7f9fSRichard Henderson         tmp_1 = tcg_const_i32(1);
1236ee8c7f9fSRichard Henderson         tcg_gen_st_i32(tmp_1, cpu_env,
1237ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1238ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1239ee8c7f9fSRichard Henderson         tcg_temp_free_i32(tmp_1);
1240ee8c7f9fSRichard Henderson 
1241ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1242ee8c7f9fSRichard Henderson 
1243ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1244ee8c7f9fSRichard Henderson     }
1245ee8c7f9fSRichard Henderson 
1246ee8c7f9fSRichard Henderson     /*
1247ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1248ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1249ee8c7f9fSRichard Henderson      * code immediately.
1250ee8c7f9fSRichard Henderson      *
1251ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1252ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1253ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1254ee8c7f9fSRichard Henderson      *
1255ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1256ee8c7f9fSRichard Henderson      */
125743b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
1258ee8c7f9fSRichard Henderson     return true;
1259ee8c7f9fSRichard Henderson }
1260ee8c7f9fSRichard Henderson 
1261e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1262e6cb0354SRichard Henderson {
1263e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1264e6cb0354SRichard Henderson         return true;
1265e6cb0354SRichard Henderson     }
1266e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1267e6cb0354SRichard Henderson     setup_dslot(dc, true);
1268e6cb0354SRichard Henderson 
1269e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1270e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1271e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1272e6cb0354SRichard Henderson     return true;
1273e6cb0354SRichard Henderson }
1274e6cb0354SRichard Henderson 
1275e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1276e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1277e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1278e6cb0354SRichard Henderson 
1279e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1280e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1281e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1282e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1283e6cb0354SRichard Henderson 
128420800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
128520800179SRichard Henderson {
128620800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
128720800179SRichard Henderson     if (dc->cpu->cfg.opcode_0_illegal) {
128820800179SRichard Henderson         trap_illegal(dc, true);
128920800179SRichard Henderson         return true;
129020800179SRichard Henderson     }
129120800179SRichard Henderson     /*
129220800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
129320800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
129420800179SRichard Henderson      */
129520800179SRichard Henderson     return false;
1296fcf5ef2aSThomas Huth }
1297fcf5ef2aSThomas Huth 
12981074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1299fcf5ef2aSThomas Huth {
13001074c0fbSRichard Henderson     TCGv_i32 t;
13011074c0fbSRichard Henderson 
13021074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
13031074c0fbSRichard Henderson     t = tcg_temp_new_i32();
13041074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13051074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
13061074c0fbSRichard Henderson     tcg_temp_free_i32(t);
1307fcf5ef2aSThomas Huth }
1308fcf5ef2aSThomas Huth 
1309536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1310536e340fSRichard Henderson {
1311536e340fSRichard Henderson     uint32_t imm = arg->imm;
1312536e340fSRichard Henderson 
1313536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1314536e340fSRichard Henderson         return true;
1315536e340fSRichard Henderson     }
1316536e340fSRichard Henderson 
1317536e340fSRichard Henderson     if (arg->rd) {
1318536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1319536e340fSRichard Henderson     }
1320536e340fSRichard Henderson 
1321536e340fSRichard Henderson     /*
1322536e340fSRichard Henderson      * Handle the carry bit separately.
1323536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1324536e340fSRichard Henderson      */
1325536e340fSRichard Henderson     if (imm & MSR_C) {
1326536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1327536e340fSRichard Henderson     }
1328536e340fSRichard Henderson 
1329536e340fSRichard Henderson     /*
1330536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1331536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1332536e340fSRichard Henderson      */
1333536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1334536e340fSRichard Henderson 
1335536e340fSRichard Henderson     if (imm != 0) {
1336536e340fSRichard Henderson         if (set) {
1337536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1338536e340fSRichard Henderson         } else {
1339536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1340536e340fSRichard Henderson         }
134143b34134SRichard Henderson         dc->base.is_jmp = DISAS_EXIT_NEXT;
1342536e340fSRichard Henderson     }
1343536e340fSRichard Henderson     return true;
1344536e340fSRichard Henderson }
1345536e340fSRichard Henderson 
1346536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1347536e340fSRichard Henderson {
1348536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1349536e340fSRichard Henderson }
1350536e340fSRichard Henderson 
1351536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1352536e340fSRichard Henderson {
1353536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1354536e340fSRichard Henderson }
1355536e340fSRichard Henderson 
13569df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
1357fcf5ef2aSThomas Huth {
13589df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
13599df297a2SRichard Henderson         return true;
1360f0f7e7f7SEdgar E. Iglesias     }
1361f0f7e7f7SEdgar E. Iglesias 
13629df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
13639df297a2SRichard Henderson     g_assert_not_reached();
13649df297a2SRichard Henderson #else
13659df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
13669df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
13679df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
13689df297a2SRichard Henderson         return true;
13692023e9a3SEdgar E. Iglesias     }
1370fcf5ef2aSThomas Huth 
13719df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
13729df297a2SRichard Henderson     switch (arg->rs) {
1373aa28e6d4SRichard Henderson     case SR_MSR:
137443b34134SRichard Henderson         /* Install MSR_C.  */
137543b34134SRichard Henderson         tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
137643b34134SRichard Henderson         /*
137743b34134SRichard Henderson          * Clear MSR_C and MSR_CC;
137843b34134SRichard Henderson          * MSR_PVR is not writable, and is always clear.
137943b34134SRichard Henderson          */
138043b34134SRichard Henderson         tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
1381fcf5ef2aSThomas Huth         break;
13829df297a2SRichard Henderson     case SR_FSR:
13839df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr));
13849df297a2SRichard Henderson         break;
13859df297a2SRichard Henderson     case 0x800:
13869df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr));
13879df297a2SRichard Henderson         break;
13889df297a2SRichard Henderson     case 0x802:
13899df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr));
13909df297a2SRichard Henderson         break;
13919df297a2SRichard Henderson 
13929df297a2SRichard Henderson     case 0x1000: /* PID */
13939df297a2SRichard Henderson     case 0x1001: /* ZPR */
13949df297a2SRichard Henderson     case 0x1002: /* TLBX */
13959df297a2SRichard Henderson     case 0x1003: /* TLBLO */
13969df297a2SRichard Henderson     case 0x1004: /* TLBHI */
13979df297a2SRichard Henderson     case 0x1005: /* TLBSX */
13989df297a2SRichard Henderson         {
13999df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
14009df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
14019df297a2SRichard Henderson 
14029df297a2SRichard Henderson             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src);
14039df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
14049df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
14059df297a2SRichard Henderson         }
14069df297a2SRichard Henderson         break;
14079df297a2SRichard Henderson 
14089df297a2SRichard Henderson     default:
14099df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14109df297a2SRichard Henderson         return true;
14119df297a2SRichard Henderson     }
141243b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
14139df297a2SRichard Henderson     return true;
14149df297a2SRichard Henderson #endif
14159df297a2SRichard Henderson }
14169df297a2SRichard Henderson 
14179df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14189df297a2SRichard Henderson {
14199df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
14209df297a2SRichard Henderson 
14219df297a2SRichard Henderson     if (arg->e) {
14229df297a2SRichard Henderson         switch (arg->rs) {
1423351527b7SEdgar E. Iglesias         case SR_EAR:
1424dbdb77c4SRichard Henderson             {
1425dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
14269df297a2SRichard Henderson                 tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
14279df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1428dbdb77c4SRichard Henderson                 tcg_temp_free_i64(t64);
1429dbdb77c4SRichard Henderson             }
14309df297a2SRichard Henderson             return true;
14319df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14329df297a2SRichard Henderson         case 0x1003: /* TLBLO */
14339df297a2SRichard Henderson             /* Handled below. */
1434aa28e6d4SRichard Henderson             break;
14359df297a2SRichard Henderson #endif
14369df297a2SRichard Henderson         case 0x2006 ... 0x2009:
14379df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
14389df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
14399df297a2SRichard Henderson             return true;
1440fcf5ef2aSThomas Huth         default:
14419df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
14429df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
14439df297a2SRichard Henderson             return true;
1444fcf5ef2aSThomas Huth         }
14459df297a2SRichard Henderson     }
14469df297a2SRichard Henderson 
14479df297a2SRichard Henderson     switch (arg->rs) {
1448aa28e6d4SRichard Henderson     case SR_PC:
14499df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
1450fcf5ef2aSThomas Huth         break;
1451aa28e6d4SRichard Henderson     case SR_MSR:
14529df297a2SRichard Henderson         msr_read(dc, dest);
1453fcf5ef2aSThomas Huth         break;
1454351527b7SEdgar E. Iglesias     case SR_EAR:
1455dbdb77c4SRichard Henderson         {
1456dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1457dbdb77c4SRichard Henderson             tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
14589df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1459dbdb77c4SRichard Henderson             tcg_temp_free_i64(t64);
1460a1b48e3aSEdgar E. Iglesias         }
1461aa28e6d4SRichard Henderson         break;
1462351527b7SEdgar E. Iglesias     case SR_ESR:
14639df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr));
1464aa28e6d4SRichard Henderson         break;
1465351527b7SEdgar E. Iglesias     case SR_FSR:
14669df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr));
1467aa28e6d4SRichard Henderson         break;
1468351527b7SEdgar E. Iglesias     case SR_BTR:
14699df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr));
1470aa28e6d4SRichard Henderson         break;
14717cdae31dSTong Ho     case SR_EDR:
14729df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr));
1473fcf5ef2aSThomas Huth         break;
1474fcf5ef2aSThomas Huth     case 0x800:
14759df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr));
1476fcf5ef2aSThomas Huth         break;
1477fcf5ef2aSThomas Huth     case 0x802:
14789df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr));
1479fcf5ef2aSThomas Huth         break;
14809df297a2SRichard Henderson 
14819df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14829df297a2SRichard Henderson     case 0x1000: /* PID */
14839df297a2SRichard Henderson     case 0x1001: /* ZPR */
14849df297a2SRichard Henderson     case 0x1002: /* TLBX */
14859df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14869df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14879df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14889df297a2SRichard Henderson         {
14899df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
14909df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
14919df297a2SRichard Henderson 
14929df297a2SRichard Henderson             gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg);
14939df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
14949df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
14959df297a2SRichard Henderson         }
14969df297a2SRichard Henderson         break;
14979df297a2SRichard Henderson #endif
14989df297a2SRichard Henderson 
1499351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
15009df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env,
15019df297a2SRichard Henderson                        offsetof(CPUMBState, pvr.regs[arg->rs - 0x2000]));
1502fcf5ef2aSThomas Huth         break;
1503fcf5ef2aSThomas Huth     default:
15049df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1505fcf5ef2aSThomas Huth         break;
1506fcf5ef2aSThomas Huth     }
15079df297a2SRichard Henderson     return true;
1508fcf5ef2aSThomas Huth }
1509fcf5ef2aSThomas Huth 
15103fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
1511fcf5ef2aSThomas Huth {
15123fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1513fcf5ef2aSThomas Huth 
15143fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15153fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15163fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15173fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15183fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15193fb394fdSRichard Henderson 
15203fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1521fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTI_FLAG;
1522fcf5ef2aSThomas Huth }
1523fcf5ef2aSThomas Huth 
15243fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
1525fcf5ef2aSThomas Huth {
15263fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1527fcf5ef2aSThomas Huth 
15283fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15293fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15303fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15313fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15323fb394fdSRichard Henderson 
15333fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1534fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTB_FLAG;
1535fcf5ef2aSThomas Huth }
1536fcf5ef2aSThomas Huth 
15373fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
1538fcf5ef2aSThomas Huth {
15393fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1540fcf5ef2aSThomas Huth 
15413fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15423fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15433fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15443fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15453fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1546fcf5ef2aSThomas Huth 
15473fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1548fcf5ef2aSThomas Huth     dc->tb_flags &= ~DRTE_FLAG;
1549fcf5ef2aSThomas Huth }
1550fcf5ef2aSThomas Huth 
1551fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
155252065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1553fcf5ef2aSThomas Huth {
1554fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1555fcf5ef2aSThomas Huth 
1556bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
155752065d8fSRichard Henderson         return true;
1558fcf5ef2aSThomas Huth     }
1559fcf5ef2aSThomas Huth 
1560cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
156152065d8fSRichard Henderson     if (rb) {
156252065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1563fcf5ef2aSThomas Huth     } else {
156452065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
1565fcf5ef2aSThomas Huth     }
1566fcf5ef2aSThomas Huth 
1567cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
156852065d8fSRichard Henderson     gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
1569cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1570cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
157152065d8fSRichard Henderson     return true;
157252065d8fSRichard Henderson }
157352065d8fSRichard Henderson 
157452065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
157552065d8fSRichard Henderson {
157652065d8fSRichard Henderson     return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
157752065d8fSRichard Henderson }
157852065d8fSRichard Henderson 
157952065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
158052065d8fSRichard Henderson {
158152065d8fSRichard Henderson     return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
158252065d8fSRichard Henderson }
158352065d8fSRichard Henderson 
158452065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
158552065d8fSRichard Henderson {
158652065d8fSRichard Henderson     TCGv_i32 t_id, t_ctrl;
158752065d8fSRichard Henderson 
158852065d8fSRichard Henderson     if (trap_userspace(dc, true)) {
158952065d8fSRichard Henderson         return true;
159052065d8fSRichard Henderson     }
159152065d8fSRichard Henderson 
159252065d8fSRichard Henderson     t_id = tcg_temp_new_i32();
159352065d8fSRichard Henderson     if (rb) {
159452065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
159552065d8fSRichard Henderson     } else {
159652065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
159752065d8fSRichard Henderson     }
159852065d8fSRichard Henderson 
159952065d8fSRichard Henderson     t_ctrl = tcg_const_i32(ctrl);
160052065d8fSRichard Henderson     gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
160152065d8fSRichard Henderson     tcg_temp_free_i32(t_id);
160252065d8fSRichard Henderson     tcg_temp_free_i32(t_ctrl);
160352065d8fSRichard Henderson     return true;
160452065d8fSRichard Henderson }
160552065d8fSRichard Henderson 
160652065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
160752065d8fSRichard Henderson {
160852065d8fSRichard Henderson     return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
160952065d8fSRichard Henderson }
161052065d8fSRichard Henderson 
161152065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
161252065d8fSRichard Henderson {
161352065d8fSRichard Henderson     return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1614fcf5ef2aSThomas Huth }
1615fcf5ef2aSThomas Huth 
1616372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1617fcf5ef2aSThomas Huth {
1618372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1619372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1620372122e3SRichard Henderson     int bound;
1621fcf5ef2aSThomas Huth 
1622fcf5ef2aSThomas Huth     dc->cpu = cpu;
1623683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1624d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
162520800179SRichard Henderson     dc->r0 = NULL;
162620800179SRichard Henderson     dc->r0_set = false;
1627287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
1628b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1629b9c58aabSRichard Henderson     dc->jmp_dest = -1;
1630fcf5ef2aSThomas Huth 
1631372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1632372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1633fcf5ef2aSThomas Huth }
1634fcf5ef2aSThomas Huth 
1635372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1636fcf5ef2aSThomas Huth {
1637fcf5ef2aSThomas Huth }
1638fcf5ef2aSThomas Huth 
1639372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1640372122e3SRichard Henderson {
1641683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1642683a247eSRichard Henderson 
1643683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1644683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1645372122e3SRichard Henderson }
1646fcf5ef2aSThomas Huth 
1647372122e3SRichard Henderson static bool mb_tr_breakpoint_check(DisasContextBase *dcb, CPUState *cs,
1648372122e3SRichard Henderson                                    const CPUBreakpoint *bp)
1649372122e3SRichard Henderson {
1650372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1651372122e3SRichard Henderson 
1652372122e3SRichard Henderson     gen_raise_exception_sync(dc, EXCP_DEBUG);
1653372122e3SRichard Henderson 
1654372122e3SRichard Henderson     /*
1655372122e3SRichard Henderson      * The address covered by the breakpoint must be included in
1656372122e3SRichard Henderson      * [tb->pc, tb->pc + tb->size) in order to for it to be
1657372122e3SRichard Henderson      * properly cleared -- thus we increment the PC here so that
1658372122e3SRichard Henderson      * the logic setting tb->size below does the right thing.
1659372122e3SRichard Henderson      */
1660372122e3SRichard Henderson     dc->base.pc_next += 4;
1661372122e3SRichard Henderson     return true;
1662372122e3SRichard Henderson }
1663372122e3SRichard Henderson 
1664372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1665372122e3SRichard Henderson {
1666372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1667372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
166844d1432bSRichard Henderson     uint32_t ir;
1669372122e3SRichard Henderson 
1670372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1671372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1672372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1673372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1674fcf5ef2aSThomas Huth     }
1675fcf5ef2aSThomas Huth 
16766f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
16776f9642d7SRichard Henderson 
167844d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
167944d1432bSRichard Henderson     if (!decode(dc, ir)) {
1680921afa9dSRichard Henderson         trap_illegal(dc, true);
168144d1432bSRichard Henderson     }
168220800179SRichard Henderson 
168320800179SRichard Henderson     if (dc->r0) {
168420800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
168520800179SRichard Henderson         dc->r0 = NULL;
168620800179SRichard Henderson         dc->r0_set = false;
168720800179SRichard Henderson     }
168820800179SRichard Henderson 
16896f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
16906f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1691d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1692372122e3SRichard Henderson     }
16936f9642d7SRichard Henderson 
16941e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
16956f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1696d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1697fcf5ef2aSThomas Huth 
1698b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
1699*3d35bcc2SRichard Henderson         /*
1700*3d35bcc2SRichard Henderson          * Finish any return-from branch.
1701*3d35bcc2SRichard Henderson          * TODO: Diagnose rtXd in delay slot of rtYd earlier.
1702*3d35bcc2SRichard Henderson          */
1703372122e3SRichard Henderson         if (dc->tb_flags & DRTI_FLAG) {
1704fcf5ef2aSThomas Huth             do_rti(dc);
1705b9c58aabSRichard Henderson         } else if (dc->tb_flags & DRTB_FLAG) {
1706fcf5ef2aSThomas Huth             do_rtb(dc);
1707b9c58aabSRichard Henderson         } else if (dc->tb_flags & DRTE_FLAG) {
1708fcf5ef2aSThomas Huth             do_rte(dc);
1709372122e3SRichard Henderson         }
1710*3d35bcc2SRichard Henderson 
1711*3d35bcc2SRichard Henderson         /* Complete the branch, ending the TB. */
1712*3d35bcc2SRichard Henderson         switch (dc->base.is_jmp) {
1713*3d35bcc2SRichard Henderson         case DISAS_NORETURN:
1714*3d35bcc2SRichard Henderson             /*
1715*3d35bcc2SRichard Henderson              * E.g. illegal insn in a delay slot.  We've already exited
1716*3d35bcc2SRichard Henderson              * and will handle D_FLAG in mb_cpu_do_interrupt.
1717*3d35bcc2SRichard Henderson              */
1718*3d35bcc2SRichard Henderson             break;
1719*3d35bcc2SRichard Henderson         case DISAS_EXIT:
1720*3d35bcc2SRichard Henderson             /*
1721*3d35bcc2SRichard Henderson              * TODO: diagnose brk/brki in delay slot earlier.
1722*3d35bcc2SRichard Henderson              * This would then fold into the illegal insn case above.
1723*3d35bcc2SRichard Henderson              */
1724*3d35bcc2SRichard Henderson             break;
1725*3d35bcc2SRichard Henderson         case DISAS_NEXT:
1726*3d35bcc2SRichard Henderson             /* Normal insn a delay slot.  */
1727372122e3SRichard Henderson             dc->base.is_jmp = DISAS_JUMP;
1728*3d35bcc2SRichard Henderson             break;
1729*3d35bcc2SRichard Henderson         case DISAS_EXIT_NEXT:
1730*3d35bcc2SRichard Henderson             /*
1731*3d35bcc2SRichard Henderson              * E.g. mts insn in a delay slot.  Continue with btarget,
1732*3d35bcc2SRichard Henderson              * but still return to the main loop.
1733*3d35bcc2SRichard Henderson              */
1734*3d35bcc2SRichard Henderson             dc->base.is_jmp = DISAS_EXIT_JUMP;
1735*3d35bcc2SRichard Henderson             break;
1736*3d35bcc2SRichard Henderson         default:
1737*3d35bcc2SRichard Henderson             g_assert_not_reached();
1738*3d35bcc2SRichard Henderson         }
1739372122e3SRichard Henderson     }
1740372122e3SRichard Henderson }
1741372122e3SRichard Henderson 
1742372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1743372122e3SRichard Henderson {
1744372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1745372122e3SRichard Henderson 
1746372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1747372122e3SRichard Henderson         /* We have already exited the TB. */
1748372122e3SRichard Henderson         return;
1749372122e3SRichard Henderson     }
1750372122e3SRichard Henderson 
1751372122e3SRichard Henderson     t_sync_flags(dc);
1752372122e3SRichard Henderson 
1753372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1754372122e3SRichard Henderson     case DISAS_TOO_MANY:
1755372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1756372122e3SRichard Henderson         return;
1757372122e3SRichard Henderson 
175817e77796SRichard Henderson     case DISAS_EXIT:
1759f6278ca9SRichard Henderson         break;
1760f6278ca9SRichard Henderson     case DISAS_EXIT_NEXT:
1761f6278ca9SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1762f6278ca9SRichard Henderson         break;
1763f6278ca9SRichard Henderson     case DISAS_EXIT_JUMP:
1764f6278ca9SRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1765f6278ca9SRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1766f6278ca9SRichard Henderson         break;
1767372122e3SRichard Henderson 
1768372122e3SRichard Henderson     case DISAS_JUMP:
1769b9c58aabSRichard Henderson         if (dc->jmp_dest != -1 && !cs->singlestep_enabled) {
1770b9c58aabSRichard Henderson             /* Direct jump. */
1771b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1772b9c58aabSRichard Henderson 
1773b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1774b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1775b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1776b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1777b9c58aabSRichard Henderson 
1778b9c58aabSRichard Henderson                 /*
1779b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1780b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1781b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1782b9c58aabSRichard Henderson                  */
1783b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1784b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1785b9c58aabSRichard Henderson 
1786b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1787b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1788b9c58aabSRichard Henderson                 gen_set_label(taken);
1789b9c58aabSRichard Henderson             }
1790b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1791b9c58aabSRichard Henderson             return;
1792b9c58aabSRichard Henderson         }
1793b9c58aabSRichard Henderson 
1794b9c58aabSRichard Henderson         /* Indirect jump (or direct jump w/ singlestep) */
1795b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1796b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1797372122e3SRichard Henderson 
1798372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1799372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1800372122e3SRichard Henderson         } else {
1801372122e3SRichard Henderson             tcg_gen_exit_tb(NULL, 0);
1802372122e3SRichard Henderson         }
1803372122e3SRichard Henderson         return;
1804372122e3SRichard Henderson 
1805a2b80dbdSRichard Henderson     default:
1806a2b80dbdSRichard Henderson         g_assert_not_reached();
1807fcf5ef2aSThomas Huth     }
1808f6278ca9SRichard Henderson 
1809f6278ca9SRichard Henderson     /* Finish DISAS_EXIT_* */
1810f6278ca9SRichard Henderson     if (unlikely(cs->singlestep_enabled)) {
1811f6278ca9SRichard Henderson         gen_raise_exception(dc, EXCP_DEBUG);
1812f6278ca9SRichard Henderson     } else {
1813f6278ca9SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1814f6278ca9SRichard Henderson     }
1815fcf5ef2aSThomas Huth }
1816fcf5ef2aSThomas Huth 
1817372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1818372122e3SRichard Henderson {
1819372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1820372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1821fcf5ef2aSThomas Huth }
1822372122e3SRichard Henderson 
1823372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1824372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1825372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1826372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1827372122e3SRichard Henderson     .breakpoint_check   = mb_tr_breakpoint_check,
1828372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1829372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1830372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1831372122e3SRichard Henderson };
1832372122e3SRichard Henderson 
1833372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1834372122e3SRichard Henderson {
1835372122e3SRichard Henderson     DisasContext dc;
1836372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1837fcf5ef2aSThomas Huth }
1838fcf5ef2aSThomas Huth 
183990c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1840fcf5ef2aSThomas Huth {
1841fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1842fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
18430c3da918SRichard Henderson     uint32_t iflags;
1844fcf5ef2aSThomas Huth     int i;
1845fcf5ef2aSThomas Huth 
18460c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18470c3da918SRichard Henderson                  env->pc, env->msr,
18482e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18492e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18502e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18512e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18520c3da918SRichard Henderson 
18530c3da918SRichard Henderson     iflags = env->iflags;
18540c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18550c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18560c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18572ead1b18SJoe Komlodi     }
18580c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18590c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18600c3da918SRichard Henderson     }
18610c3da918SRichard Henderson     if (iflags & D_FLAG) {
1862b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18630c3da918SRichard Henderson     }
18640c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18650c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18660c3da918SRichard Henderson     }
18670c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18680c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18690c3da918SRichard Henderson     }
18700c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18710c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18720c3da918SRichard Henderson     }
18730c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18740c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18752ead1b18SJoe Komlodi     }
1876fcf5ef2aSThomas Huth 
18770c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
187819f27b6cSRichard Henderson                  "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
18790c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18800c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18810c3da918SRichard Henderson 
18820c3da918SRichard Henderson     for (i = 0; i < 12; i++) {
18830c3da918SRichard Henderson         qemu_fprintf(f, "rpvr%-2d=%08x%c",
18840c3da918SRichard Henderson                      i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' ');
1885fcf5ef2aSThomas Huth     }
18860c3da918SRichard Henderson 
18870c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18880c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18890c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18900c3da918SRichard Henderson     }
18910c3da918SRichard Henderson     qemu_fprintf(f, "\n");
1892fcf5ef2aSThomas Huth }
1893fcf5ef2aSThomas Huth 
1894fcf5ef2aSThomas Huth void mb_tcg_init(void)
1895fcf5ef2aSThomas Huth {
1896480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1897480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1898fcf5ef2aSThomas Huth 
1899480d29a8SRichard Henderson     static const struct {
1900480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1901480d29a8SRichard Henderson     } i32s[] = {
1902e47c2231SRichard Henderson         /*
1903e47c2231SRichard Henderson          * Note that r0 is handled specially in reg_for_read
1904e47c2231SRichard Henderson          * and reg_for_write.  Nothing should touch cpu_R[0].
1905e47c2231SRichard Henderson          * Leave that element NULL, which will assert quickly
1906e47c2231SRichard Henderson          * inside the tcg generator functions.
1907e47c2231SRichard Henderson          */
1908e47c2231SRichard Henderson                R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1909480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1910480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1911480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1912480d29a8SRichard Henderson 
1913480d29a8SRichard Henderson         SP(pc),
1914480d29a8SRichard Henderson         SP(msr),
19151074c0fbSRichard Henderson         SP(msr_c),
1916480d29a8SRichard Henderson         SP(imm),
1917480d29a8SRichard Henderson         SP(iflags),
1918b9c58aabSRichard Henderson         SP(bvalue),
1919480d29a8SRichard Henderson         SP(btarget),
1920480d29a8SRichard Henderson         SP(res_val),
1921480d29a8SRichard Henderson     };
1922480d29a8SRichard Henderson 
1923480d29a8SRichard Henderson #undef R
1924480d29a8SRichard Henderson #undef SP
1925480d29a8SRichard Henderson 
1926480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1927480d29a8SRichard Henderson         *i32s[i].var =
1928480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1929fcf5ef2aSThomas Huth     }
193076e8187dSRichard Henderson 
1931480d29a8SRichard Henderson     cpu_res_addr =
1932480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1933fcf5ef2aSThomas Huth }
1934fcf5ef2aSThomas Huth 
1935fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1936fcf5ef2aSThomas Huth                           target_ulong *data)
1937fcf5ef2aSThomas Huth {
193876e8187dSRichard Henderson     env->pc = data[0];
1939683a247eSRichard Henderson     env->iflags = data[1];
1940fcf5ef2aSThomas Huth }
1941