xref: /openbmc/qemu/target/microblaze/translate.c (revision 8eb806a763f4a804ac80a6d4f4679c60fd66d8fa)
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
10ee452036SChetan Pant  * version 2.1 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 "exec/log.h"
33fcf5ef2aSThomas Huth 
34fcf5ef2aSThomas Huth #define EXTRACT_FIELD(src, start, end) \
35fcf5ef2aSThomas Huth             (((src) >> start) & ((1 << (end - start + 1)) - 1))
36fcf5ef2aSThomas Huth 
3777fc6f5eSLluís Vilanova /* is_jmp field values */
3877fc6f5eSLluís Vilanova #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
3917e77796SRichard Henderson #define DISAS_EXIT    DISAS_TARGET_1 /* all cpu state modified dynamically */
4077fc6f5eSLluís Vilanova 
41f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to next */
42f6278ca9SRichard Henderson #define DISAS_EXIT_NEXT DISAS_TARGET_2
43f6278ca9SRichard Henderson /* cpu state besides pc was modified dynamically; update pc to btarget */
44f6278ca9SRichard Henderson #define DISAS_EXIT_JUMP DISAS_TARGET_3
45f6278ca9SRichard Henderson 
46cfeea807SEdgar E. Iglesias static TCGv_i32 cpu_R[32];
470f96e96bSRichard Henderson static TCGv_i32 cpu_pc;
483e0e16aeSRichard Henderson static TCGv_i32 cpu_msr;
491074c0fbSRichard Henderson static TCGv_i32 cpu_msr_c;
509b158558SRichard Henderson static TCGv_i32 cpu_imm;
51b9c58aabSRichard Henderson static TCGv_i32 cpu_bvalue;
520f96e96bSRichard Henderson static TCGv_i32 cpu_btarget;
539b158558SRichard Henderson static TCGv_i32 cpu_iflags;
549b158558SRichard Henderson static TCGv cpu_res_addr;
559b158558SRichard Henderson static TCGv_i32 cpu_res_val;
56fcf5ef2aSThomas Huth 
57fcf5ef2aSThomas Huth #include "exec/gen-icount.h"
58fcf5ef2aSThomas Huth 
59fcf5ef2aSThomas Huth /* This is the state at translation time.  */
60fcf5ef2aSThomas Huth typedef struct DisasContext {
61d4705ae0SRichard Henderson     DisasContextBase base;
624b893631SRichard Henderson     const MicroBlazeCPUConfig *cfg;
63fcf5ef2aSThomas Huth 
64683a247eSRichard Henderson     /* TCG op of the current insn_start.  */
65683a247eSRichard Henderson     TCGOp *insn_start;
66683a247eSRichard Henderson 
6720800179SRichard Henderson     TCGv_i32 r0;
6820800179SRichard Henderson     bool r0_set;
6920800179SRichard Henderson 
70fcf5ef2aSThomas Huth     /* Decoder.  */
71d7ecb757SRichard Henderson     uint32_t ext_imm;
72683a247eSRichard Henderson     unsigned int tb_flags;
736f9642d7SRichard Henderson     unsigned int tb_flags_to_set;
74287b1defSRichard Henderson     int mem_index;
75fcf5ef2aSThomas Huth 
76b9c58aabSRichard Henderson     /* Condition under which to jump, including NEVER and ALWAYS. */
77b9c58aabSRichard Henderson     TCGCond jmp_cond;
78b9c58aabSRichard Henderson 
79b9c58aabSRichard Henderson     /* Immediate branch-taken destination, or -1 for indirect. */
80b9c58aabSRichard Henderson     uint32_t jmp_dest;
81fcf5ef2aSThomas Huth } DisasContext;
82fcf5ef2aSThomas Huth 
8320800179SRichard Henderson static int typeb_imm(DisasContext *dc, int x)
8420800179SRichard Henderson {
8520800179SRichard Henderson     if (dc->tb_flags & IMM_FLAG) {
8620800179SRichard Henderson         return deposit32(dc->ext_imm, 0, 16, x);
8720800179SRichard Henderson     }
8820800179SRichard Henderson     return x;
8920800179SRichard Henderson }
9020800179SRichard Henderson 
9144d1432bSRichard Henderson /* Include the auto-generated decoder.  */
9244d1432bSRichard Henderson #include "decode-insns.c.inc"
9344d1432bSRichard Henderson 
94683a247eSRichard Henderson static void t_sync_flags(DisasContext *dc)
95fcf5ef2aSThomas Huth {
96fcf5ef2aSThomas Huth     /* Synch the tb dependent flags between translator and runtime.  */
9788e74b61SRichard Henderson     if ((dc->tb_flags ^ dc->base.tb->flags) & IFLAGS_TB_MASK) {
9888e74b61SRichard Henderson         tcg_gen_movi_i32(cpu_iflags, dc->tb_flags & IFLAGS_TB_MASK);
99fcf5ef2aSThomas Huth     }
100fcf5ef2aSThomas Huth }
101fcf5ef2aSThomas Huth 
10241ba37c4SRichard Henderson static void gen_raise_exception(DisasContext *dc, uint32_t index)
103fcf5ef2aSThomas Huth {
104fcf5ef2aSThomas Huth     TCGv_i32 tmp = tcg_const_i32(index);
105fcf5ef2aSThomas Huth 
106fcf5ef2aSThomas Huth     gen_helper_raise_exception(cpu_env, tmp);
107fcf5ef2aSThomas Huth     tcg_temp_free_i32(tmp);
108d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
109fcf5ef2aSThomas Huth }
110fcf5ef2aSThomas Huth 
11141ba37c4SRichard Henderson static void gen_raise_exception_sync(DisasContext *dc, uint32_t index)
11241ba37c4SRichard Henderson {
11341ba37c4SRichard Henderson     t_sync_flags(dc);
114d4705ae0SRichard Henderson     tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
11541ba37c4SRichard Henderson     gen_raise_exception(dc, index);
11641ba37c4SRichard Henderson }
11741ba37c4SRichard Henderson 
11841ba37c4SRichard Henderson static void gen_raise_hw_excp(DisasContext *dc, uint32_t esr_ec)
11941ba37c4SRichard Henderson {
12041ba37c4SRichard Henderson     TCGv_i32 tmp = tcg_const_i32(esr_ec);
12141ba37c4SRichard Henderson     tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUMBState, esr));
12241ba37c4SRichard Henderson     tcg_temp_free_i32(tmp);
12341ba37c4SRichard Henderson 
12441ba37c4SRichard Henderson     gen_raise_exception_sync(dc, EXCP_HW_EXCP);
12541ba37c4SRichard Henderson }
12641ba37c4SRichard Henderson 
127fcf5ef2aSThomas Huth static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
128fcf5ef2aSThomas Huth {
12966345580SRichard Henderson     if (translator_use_goto_tb(&dc->base, dest)) {
130fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1310f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
132d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
133fcf5ef2aSThomas Huth     } else {
1340f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1354059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
136fcf5ef2aSThomas Huth     }
137d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
138fcf5ef2aSThomas Huth }
139fcf5ef2aSThomas Huth 
140bdfc1e88SEdgar E. Iglesias /*
1419ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1429ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1439ba8cd45SEdgar E. Iglesias  */
1449ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1459ba8cd45SEdgar E. Iglesias {
1462c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1474b893631SRichard Henderson         && dc->cfg->illegal_opcode_exception) {
14841ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1499ba8cd45SEdgar E. Iglesias     }
1509ba8cd45SEdgar E. Iglesias     return cond;
1519ba8cd45SEdgar E. Iglesias }
1529ba8cd45SEdgar E. Iglesias 
1539ba8cd45SEdgar E. Iglesias /*
154bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
155bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
156bdfc1e88SEdgar E. Iglesias  */
157bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
158bdfc1e88SEdgar E. Iglesias {
159287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
160bdfc1e88SEdgar E. Iglesias 
1612c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
16241ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
163bdfc1e88SEdgar E. Iglesias     }
164bdfc1e88SEdgar E. Iglesias     return cond_user;
165bdfc1e88SEdgar E. Iglesias }
166bdfc1e88SEdgar E. Iglesias 
1672a7567a2SRichard Henderson /*
1682a7567a2SRichard Henderson  * Return true, and log an error, if the current insn is
1692a7567a2SRichard Henderson  * within a delay slot.
1702a7567a2SRichard Henderson  */
1712a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
1722a7567a2SRichard Henderson {
1732a7567a2SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1742a7567a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
1752a7567a2SRichard Henderson                       "Invalid insn in delay slot: %s at %08x\n",
1762a7567a2SRichard Henderson                       insn_type, (uint32_t)dc->base.pc_next);
1772a7567a2SRichard Henderson         return true;
1782a7567a2SRichard Henderson     }
1792a7567a2SRichard Henderson     return false;
1802a7567a2SRichard Henderson }
1812a7567a2SRichard Henderson 
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) \
2794b893631SRichard Henderson     { return dc->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) \
2874b893631SRichard Henderson     { return dc->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) \
2954b893631SRichard Henderson     { return dc->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 {
5032a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "imm")) {
5042a7567a2SRichard Henderson         return true;
5052a7567a2SRichard Henderson     }
506e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
507e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
5086f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
509e64b2e5cSRichard Henderson     return true;
510e64b2e5cSRichard Henderson }
511e64b2e5cSRichard Henderson 
51297955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
51397955cebSRichard Henderson {
51497955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
51597955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
51697955cebSRichard Henderson     tcg_temp_free_i32(tmp);
51797955cebSRichard Henderson }
51897955cebSRichard Henderson 
51997955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
52097955cebSRichard Henderson {
52197955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
52297955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
52397955cebSRichard Henderson     tcg_temp_free_i32(tmp);
52497955cebSRichard Henderson }
52597955cebSRichard Henderson 
52697955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
52797955cebSRichard Henderson {
52897955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
52997955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
53097955cebSRichard Henderson     tcg_temp_free_i32(tmp);
53197955cebSRichard Henderson }
53297955cebSRichard Henderson 
53397955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
53497955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
53597955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
53697955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
53797955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
53897955cebSRichard Henderson 
539cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
540cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
541cb0a0a4cSRichard Henderson 
542607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
543607f5767SRichard Henderson {
544607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
545607f5767SRichard Henderson }
546607f5767SRichard Henderson 
547607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
548607f5767SRichard Henderson {
549607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
550607f5767SRichard Henderson }
551607f5767SRichard Henderson 
552607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
553607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
554607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
555607f5767SRichard Henderson 
556a2b0b90eSRichard Henderson /* No input carry, but output carry. */
557a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
558a2b0b90eSRichard Henderson {
559a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
560a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
561a2b0b90eSRichard Henderson }
562a2b0b90eSRichard Henderson 
563a2b0b90eSRichard Henderson /* Input and output carry. */
564a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
565a2b0b90eSRichard Henderson {
566a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
567a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
568a2b0b90eSRichard Henderson 
569a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
570a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
571a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
572a2b0b90eSRichard Henderson 
573a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
574a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
575a2b0b90eSRichard Henderson }
576a2b0b90eSRichard Henderson 
577a2b0b90eSRichard Henderson /* No input or output carry. */
578a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
579a2b0b90eSRichard Henderson {
580a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
581a2b0b90eSRichard Henderson }
582a2b0b90eSRichard Henderson 
583a2b0b90eSRichard Henderson /* Input carry, no output carry. */
584a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
585a2b0b90eSRichard Henderson {
586a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
587a2b0b90eSRichard Henderson 
588a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
589a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
590a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
591a2b0b90eSRichard Henderson 
592a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
593a2b0b90eSRichard Henderson }
594a2b0b90eSRichard Henderson 
595a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
596a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
597a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
598a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
599a2b0b90eSRichard Henderson 
600a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
601a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
602a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
603a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
604a2b0b90eSRichard Henderson 
60539cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
60639cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
60739cf3864SRichard Henderson 
60839cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
60939cf3864SRichard Henderson {
61039cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
61139cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
61239cf3864SRichard Henderson }
61339cf3864SRichard Henderson 
61439cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
61539cf3864SRichard Henderson {
61639cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
61739cf3864SRichard Henderson 
61839cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
61939cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
62039cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
62139cf3864SRichard Henderson 
62239cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
62339cf3864SRichard Henderson }
62439cf3864SRichard Henderson 
62539cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
62639cf3864SRichard Henderson {
62739cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
62839cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
62939cf3864SRichard Henderson }
63039cf3864SRichard Henderson 
63139cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
63239cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
63339cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
63439cf3864SRichard Henderson 
63539cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
63639cf3864SRichard Henderson {
63739cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
63839cf3864SRichard Henderson }
63939cf3864SRichard Henderson 
64039cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
64139cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
64239cf3864SRichard Henderson 
64339cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
64439cf3864SRichard Henderson {
64539cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
64639cf3864SRichard Henderson     trap_userspace(dc, true);
64739cf3864SRichard Henderson     return true;
64839cf3864SRichard Henderson }
64939cf3864SRichard Henderson 
650cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
651cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
652cb0a0a4cSRichard Henderson 
653d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
654d8e59c4aSRichard Henderson {
655d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
656d8e59c4aSRichard Henderson 
657d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
658d8e59c4aSRichard Henderson     if (ra && rb) {
659d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
660d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
661d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
662d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
663d8e59c4aSRichard Henderson     } else if (ra) {
664d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
665d8e59c4aSRichard Henderson     } else if (rb) {
666d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
667d8e59c4aSRichard Henderson     } else {
668d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
669d8e59c4aSRichard Henderson     }
670d8e59c4aSRichard Henderson 
6714b893631SRichard Henderson     if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
672d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
673d8e59c4aSRichard Henderson     }
674d8e59c4aSRichard Henderson     return ret;
675d8e59c4aSRichard Henderson }
676d8e59c4aSRichard Henderson 
677d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
678d8e59c4aSRichard Henderson {
679d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
680d8e59c4aSRichard Henderson 
681d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
682d8e59c4aSRichard Henderson     if (ra) {
683d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
684d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
685d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
686d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
687d8e59c4aSRichard Henderson     } else {
688d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
689d8e59c4aSRichard Henderson     }
690d8e59c4aSRichard Henderson 
6914b893631SRichard Henderson     if (ra == 1 && dc->cfg->stackprot) {
692d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
693d8e59c4aSRichard Henderson     }
694d8e59c4aSRichard Henderson     return ret;
695d8e59c4aSRichard Henderson }
696d8e59c4aSRichard Henderson 
69719f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
698d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
699d8e59c4aSRichard Henderson {
7004b893631SRichard Henderson     int addr_size = dc->cfg->addr_size;
701d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
702d8e59c4aSRichard Henderson 
703d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
704d8e59c4aSRichard Henderson         if (rb) {
705d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
706d8e59c4aSRichard Henderson         } else {
707d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
708d8e59c4aSRichard Henderson         }
709d8e59c4aSRichard Henderson     } else {
710d8e59c4aSRichard Henderson         if (rb) {
711d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
712d8e59c4aSRichard Henderson         } else {
713d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
714d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
715d8e59c4aSRichard Henderson         }
716d8e59c4aSRichard Henderson         if (addr_size < 64) {
717d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
718d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
719d8e59c4aSRichard Henderson         }
720d8e59c4aSRichard Henderson     }
721d8e59c4aSRichard Henderson     return ret;
722d8e59c4aSRichard Henderson }
72319f27b6cSRichard Henderson #endif
724d8e59c4aSRichard Henderson 
725b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
726ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
727ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
728ab0c8d0fSRichard Henderson {
729ab0c8d0fSRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
730ab0c8d0fSRichard Henderson 
731ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
732ab0c8d0fSRichard Henderson     iflags |= rd << 5;
733ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
734ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
735ab0c8d0fSRichard Henderson 
736ab0c8d0fSRichard Henderson     tcg_set_insn_start_param(dc->insn_start, 1, iflags);
737ab0c8d0fSRichard Henderson }
738b414df75SRichard Henderson #endif
739ab0c8d0fSRichard Henderson 
740d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
741d8e59c4aSRichard Henderson                     int mem_index, bool rev)
742d8e59c4aSRichard Henderson {
743d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
744d8e59c4aSRichard Henderson 
745d8e59c4aSRichard Henderson     /*
746d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
747d8e59c4aSRichard Henderson      *
748d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
749d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
750d8e59c4aSRichard Henderson      */
751d8e59c4aSRichard Henderson     if (rev) {
752d8e59c4aSRichard Henderson         if (size > MO_8) {
753d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
754d8e59c4aSRichard Henderson         }
755d8e59c4aSRichard Henderson         if (size < MO_32) {
756d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
757d8e59c4aSRichard Henderson         }
758d8e59c4aSRichard Henderson     }
759d8e59c4aSRichard Henderson 
760b414df75SRichard Henderson     /*
761b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
762b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
763b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
764b414df75SRichard Henderson      */
765b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
766ab0c8d0fSRichard Henderson     if (size > MO_8 &&
767ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
7684b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
769ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
770ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
771d8e59c4aSRichard Henderson     }
772b414df75SRichard Henderson #endif
773d8e59c4aSRichard Henderson 
774ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
775d8e59c4aSRichard Henderson 
776d8e59c4aSRichard Henderson     tcg_temp_free(addr);
777d8e59c4aSRichard Henderson     return true;
778d8e59c4aSRichard Henderson }
779d8e59c4aSRichard Henderson 
780d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
781d8e59c4aSRichard Henderson {
782d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
783d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
784d8e59c4aSRichard Henderson }
785d8e59c4aSRichard Henderson 
786d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
787d8e59c4aSRichard Henderson {
788d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
789d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
790d8e59c4aSRichard Henderson }
791d8e59c4aSRichard Henderson 
792d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
793d8e59c4aSRichard Henderson {
794d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
795d8e59c4aSRichard Henderson         return true;
796d8e59c4aSRichard Henderson     }
79719f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
79819f27b6cSRichard Henderson     return true;
79919f27b6cSRichard Henderson #else
800d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
801d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
80219f27b6cSRichard Henderson #endif
803d8e59c4aSRichard Henderson }
804d8e59c4aSRichard Henderson 
805d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
806d8e59c4aSRichard Henderson {
807d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
808d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
809d8e59c4aSRichard Henderson }
810d8e59c4aSRichard Henderson 
811d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
812d8e59c4aSRichard Henderson {
813d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
814d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
815d8e59c4aSRichard Henderson }
816d8e59c4aSRichard Henderson 
817d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
818d8e59c4aSRichard Henderson {
819d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
820d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
821d8e59c4aSRichard Henderson }
822d8e59c4aSRichard Henderson 
823d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
824d8e59c4aSRichard Henderson {
825d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
826d8e59c4aSRichard Henderson         return true;
827d8e59c4aSRichard Henderson     }
82819f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
82919f27b6cSRichard Henderson     return true;
83019f27b6cSRichard Henderson #else
831d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
832d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
83319f27b6cSRichard Henderson #endif
834d8e59c4aSRichard Henderson }
835d8e59c4aSRichard Henderson 
836d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
837d8e59c4aSRichard Henderson {
838d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
839d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
840d8e59c4aSRichard Henderson }
841d8e59c4aSRichard Henderson 
842d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
843d8e59c4aSRichard Henderson {
844d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
845d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
846d8e59c4aSRichard Henderson }
847d8e59c4aSRichard Henderson 
848d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
849d8e59c4aSRichard Henderson {
850d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
851d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
852d8e59c4aSRichard Henderson }
853d8e59c4aSRichard Henderson 
854d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
855d8e59c4aSRichard Henderson {
856d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
857d8e59c4aSRichard Henderson         return true;
858d8e59c4aSRichard Henderson     }
85919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
86019f27b6cSRichard Henderson     return true;
86119f27b6cSRichard Henderson #else
862d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
863d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
86419f27b6cSRichard Henderson #endif
865d8e59c4aSRichard Henderson }
866d8e59c4aSRichard Henderson 
867d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
868d8e59c4aSRichard Henderson {
869d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
870d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
871d8e59c4aSRichard Henderson }
872d8e59c4aSRichard Henderson 
873d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
874d8e59c4aSRichard Henderson {
875d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
876d8e59c4aSRichard Henderson 
877d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
878d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
879d8e59c4aSRichard Henderson 
880d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
881d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
882d8e59c4aSRichard Henderson     tcg_temp_free(addr);
883d8e59c4aSRichard Henderson 
884d8e59c4aSRichard Henderson     if (arg->rd) {
885d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
886d8e59c4aSRichard Henderson     }
887d8e59c4aSRichard Henderson 
888d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
889d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
890d8e59c4aSRichard Henderson     return true;
891d8e59c4aSRichard Henderson }
892d8e59c4aSRichard Henderson 
893d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
894d8e59c4aSRichard Henderson                      int mem_index, bool rev)
895d8e59c4aSRichard Henderson {
896d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
897d8e59c4aSRichard Henderson 
898d8e59c4aSRichard Henderson     /*
899d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
900d8e59c4aSRichard Henderson      *
901d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
902d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
903d8e59c4aSRichard Henderson      */
904d8e59c4aSRichard Henderson     if (rev) {
905d8e59c4aSRichard Henderson         if (size > MO_8) {
906d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
907d8e59c4aSRichard Henderson         }
908d8e59c4aSRichard Henderson         if (size < MO_32) {
909d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
910d8e59c4aSRichard Henderson         }
911d8e59c4aSRichard Henderson     }
912d8e59c4aSRichard Henderson 
913b414df75SRichard Henderson     /*
914b414df75SRichard Henderson      * For system mode, enforce alignment if the cpu configuration
915b414df75SRichard Henderson      * requires it.  For user-mode, the Linux kernel will have fixed up
916b414df75SRichard Henderson      * any unaligned access, so emulate that by *not* setting MO_ALIGN.
917b414df75SRichard Henderson      */
918b414df75SRichard Henderson #ifndef CONFIG_USER_ONLY
919ab0c8d0fSRichard Henderson     if (size > MO_8 &&
920ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
9214b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
922ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
923ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
924d8e59c4aSRichard Henderson     }
925b414df75SRichard Henderson #endif
926d8e59c4aSRichard Henderson 
927ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
928ab0c8d0fSRichard Henderson 
929d8e59c4aSRichard Henderson     tcg_temp_free(addr);
930d8e59c4aSRichard Henderson     return true;
931d8e59c4aSRichard Henderson }
932d8e59c4aSRichard Henderson 
933d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
934d8e59c4aSRichard Henderson {
935d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
936d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
937d8e59c4aSRichard Henderson }
938d8e59c4aSRichard Henderson 
939d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
940d8e59c4aSRichard Henderson {
941d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
942d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
943d8e59c4aSRichard Henderson }
944d8e59c4aSRichard Henderson 
945d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
946d8e59c4aSRichard Henderson {
947d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
948d8e59c4aSRichard Henderson         return true;
949d8e59c4aSRichard Henderson     }
95019f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
95119f27b6cSRichard Henderson     return true;
95219f27b6cSRichard Henderson #else
953d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
954d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
95519f27b6cSRichard Henderson #endif
956d8e59c4aSRichard Henderson }
957d8e59c4aSRichard Henderson 
958d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
959d8e59c4aSRichard Henderson {
960d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
961d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
962d8e59c4aSRichard Henderson }
963d8e59c4aSRichard Henderson 
964d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
965d8e59c4aSRichard Henderson {
966d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
967d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
968d8e59c4aSRichard Henderson }
969d8e59c4aSRichard Henderson 
970d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
971d8e59c4aSRichard Henderson {
972d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
973d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
974d8e59c4aSRichard Henderson }
975d8e59c4aSRichard Henderson 
976d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
977d8e59c4aSRichard Henderson {
978d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
979d8e59c4aSRichard Henderson         return true;
980d8e59c4aSRichard Henderson     }
98119f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
98219f27b6cSRichard Henderson     return true;
98319f27b6cSRichard Henderson #else
984d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
985d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
98619f27b6cSRichard Henderson #endif
987d8e59c4aSRichard Henderson }
988d8e59c4aSRichard Henderson 
989d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
990d8e59c4aSRichard Henderson {
991d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
992d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
993d8e59c4aSRichard Henderson }
994d8e59c4aSRichard Henderson 
995d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
996d8e59c4aSRichard Henderson {
997d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
998d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
999d8e59c4aSRichard Henderson }
1000d8e59c4aSRichard Henderson 
1001d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
1002d8e59c4aSRichard Henderson {
1003d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1004d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
1005d8e59c4aSRichard Henderson }
1006d8e59c4aSRichard Henderson 
1007d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
1008d8e59c4aSRichard Henderson {
1009d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
1010d8e59c4aSRichard Henderson         return true;
1011d8e59c4aSRichard Henderson     }
101219f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
101319f27b6cSRichard Henderson     return true;
101419f27b6cSRichard Henderson #else
1015d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1016d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
101719f27b6cSRichard Henderson #endif
1018d8e59c4aSRichard Henderson }
1019d8e59c4aSRichard Henderson 
1020d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1021d8e59c4aSRichard Henderson {
1022d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1023d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1024d8e59c4aSRichard Henderson }
1025d8e59c4aSRichard Henderson 
1026d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1027d8e59c4aSRichard Henderson {
1028d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1029d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1030d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1031d8e59c4aSRichard Henderson     TCGv_i32 tval;
1032d8e59c4aSRichard Henderson 
1033d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1034d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1035d8e59c4aSRichard Henderson 
1036d8e59c4aSRichard Henderson     /*
1037d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1038d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1039d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1040d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1041d8e59c4aSRichard Henderson      */
1042d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1043d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1044d8e59c4aSRichard Henderson 
1045d8e59c4aSRichard Henderson     /*
1046d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1047d8e59c4aSRichard Henderson      * the reserved location.
1048d8e59c4aSRichard Henderson      */
1049d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1050d8e59c4aSRichard Henderson 
1051d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1052d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1053d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1054d8e59c4aSRichard Henderson 
1055d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1056d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1057d8e59c4aSRichard Henderson 
1058d8e59c4aSRichard Henderson     /* Success */
1059d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1060d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1061d8e59c4aSRichard Henderson 
1062d8e59c4aSRichard Henderson     /* Failure */
1063d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1064d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1065d8e59c4aSRichard Henderson 
1066d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1067d8e59c4aSRichard Henderson 
1068d8e59c4aSRichard Henderson     /*
1069d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1070d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1071d8e59c4aSRichard Henderson      */
1072d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1073d8e59c4aSRichard Henderson     return true;
1074d8e59c4aSRichard Henderson }
1075d8e59c4aSRichard Henderson 
107616bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
107716bbbbc9SRichard Henderson {
107816bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
107916bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
108016bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
108116bbbbc9SRichard Henderson     }
108216bbbbc9SRichard Henderson }
108316bbbbc9SRichard Henderson 
108416bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
108516bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
108616bbbbc9SRichard Henderson {
108716bbbbc9SRichard Henderson     uint32_t add_pc;
108816bbbbc9SRichard Henderson 
10892a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "branch")) {
10902a7567a2SRichard Henderson         return true;
10912a7567a2SRichard Henderson     }
109216bbbbc9SRichard Henderson     if (delay) {
109316bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
109416bbbbc9SRichard Henderson     }
109516bbbbc9SRichard Henderson 
109616bbbbc9SRichard Henderson     if (link) {
109716bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
109816bbbbc9SRichard Henderson     }
109916bbbbc9SRichard Henderson 
110016bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
110116bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
110216bbbbc9SRichard Henderson     if (dest_rb > 0) {
110316bbbbc9SRichard Henderson         dc->jmp_dest = -1;
110416bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
110516bbbbc9SRichard Henderson     } else {
110616bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
110716bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
110816bbbbc9SRichard Henderson     }
110916bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
111016bbbbc9SRichard Henderson     return true;
111116bbbbc9SRichard Henderson }
111216bbbbc9SRichard Henderson 
111316bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
111416bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
111516bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
111616bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
111716bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
111816bbbbc9SRichard Henderson 
111916bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
112016bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
112116bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
112216bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
112316bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
112416bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
112516bbbbc9SRichard Henderson 
1126fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1127fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1128fd779113SRichard Henderson {
1129fd779113SRichard Henderson     TCGv_i32 zero, next;
1130fd779113SRichard Henderson 
11312a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "bcc")) {
11322a7567a2SRichard Henderson         return true;
11332a7567a2SRichard Henderson     }
1134fd779113SRichard Henderson     if (delay) {
1135fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1136fd779113SRichard Henderson     }
1137fd779113SRichard Henderson 
1138fd779113SRichard Henderson     dc->jmp_cond = cond;
1139fd779113SRichard Henderson 
1140fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1141fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1142fd779113SRichard Henderson 
1143fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1144fd779113SRichard Henderson     if (dest_rb > 0) {
1145fd779113SRichard Henderson         dc->jmp_dest = -1;
1146fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1147fd779113SRichard Henderson     } else {
1148fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1149fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1150fd779113SRichard Henderson     }
1151fd779113SRichard Henderson 
1152fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1153fd779113SRichard Henderson     zero = tcg_const_i32(0);
1154fd779113SRichard Henderson     next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4);
1155fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1156fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1157fd779113SRichard Henderson                         cpu_btarget, next);
1158fd779113SRichard Henderson     tcg_temp_free_i32(zero);
1159fd779113SRichard Henderson     tcg_temp_free_i32(next);
1160fd779113SRichard Henderson 
1161fd779113SRichard Henderson     return true;
1162fd779113SRichard Henderson }
1163fd779113SRichard Henderson 
1164fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1165fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1166fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1167fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1168fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1169fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1170fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1171fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1172fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1173fd779113SRichard Henderson 
1174fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1175fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1176fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1177fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1178fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1179fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1180fd779113SRichard Henderson 
1181f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1182f5235314SRichard Henderson {
1183f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1184f5235314SRichard Henderson         return true;
1185f5235314SRichard Henderson     }
11862a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brk")) {
11872a7567a2SRichard Henderson         return true;
11882a7567a2SRichard Henderson     }
11892a7567a2SRichard Henderson 
1190f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1191f5235314SRichard Henderson     if (arg->rd) {
1192f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1193f5235314SRichard Henderson     }
1194f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1195f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1196f5235314SRichard Henderson 
119717e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1198f5235314SRichard Henderson     return true;
1199f5235314SRichard Henderson }
1200f5235314SRichard Henderson 
1201f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1202f5235314SRichard Henderson {
1203f5235314SRichard Henderson     uint32_t imm = arg->imm;
1204f5235314SRichard Henderson 
1205f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1206f5235314SRichard Henderson         return true;
1207f5235314SRichard Henderson     }
12082a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brki")) {
12092a7567a2SRichard Henderson         return true;
12102a7567a2SRichard Henderson     }
12112a7567a2SRichard Henderson 
1212f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1213f5235314SRichard Henderson     if (arg->rd) {
1214f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1215f5235314SRichard Henderson     }
1216f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1217f5235314SRichard Henderson 
1218f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1219f5235314SRichard Henderson     switch (imm) {
1220f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1221f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1222f5235314SRichard Henderson         break;
1223f5235314SRichard Henderson     case 0x18: /* debug trap */
1224f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1225f5235314SRichard Henderson         break;
1226f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1227f5235314SRichard Henderson         g_assert_not_reached();
1228f5235314SRichard Henderson     }
1229f5235314SRichard Henderson #else
1230f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1231f5235314SRichard Henderson 
1232f5235314SRichard Henderson     if (imm != 0x18) {
1233f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1234f5235314SRichard Henderson     }
1235f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1236f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1237f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1238f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1239f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1240f5235314SRichard Henderson     }
1241f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
124217e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1243f5235314SRichard Henderson #endif
1244f5235314SRichard Henderson 
1245f5235314SRichard Henderson     return true;
1246f5235314SRichard Henderson }
1247f5235314SRichard Henderson 
1248ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1249ee8c7f9fSRichard Henderson {
1250ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1251ee8c7f9fSRichard Henderson 
12522a7567a2SRichard Henderson     /* Note that mbar is a specialized branch instruction. */
12532a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "mbar")) {
12542a7567a2SRichard Henderson         return true;
12552a7567a2SRichard Henderson     }
12562a7567a2SRichard Henderson 
1257ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1258ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1259ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1260ee8c7f9fSRichard Henderson     }
1261ee8c7f9fSRichard Henderson 
1262ee8c7f9fSRichard Henderson     /* Sleep. */
1263ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1264ee8c7f9fSRichard Henderson         TCGv_i32 tmp_1;
1265ee8c7f9fSRichard Henderson 
1266ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1267ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1268ee8c7f9fSRichard Henderson             return true;
1269ee8c7f9fSRichard Henderson         }
1270ee8c7f9fSRichard Henderson 
1271ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1272ee8c7f9fSRichard Henderson 
1273ee8c7f9fSRichard Henderson         tmp_1 = tcg_const_i32(1);
1274ee8c7f9fSRichard Henderson         tcg_gen_st_i32(tmp_1, cpu_env,
1275ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1276ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1277ee8c7f9fSRichard Henderson         tcg_temp_free_i32(tmp_1);
1278ee8c7f9fSRichard Henderson 
1279ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1280ee8c7f9fSRichard Henderson 
1281ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1282ee8c7f9fSRichard Henderson     }
1283ee8c7f9fSRichard Henderson 
1284ee8c7f9fSRichard Henderson     /*
1285ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1286ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1287ee8c7f9fSRichard Henderson      * code immediately.
1288ee8c7f9fSRichard Henderson      *
1289ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1290ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1291ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1292ee8c7f9fSRichard Henderson      *
1293ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1294ee8c7f9fSRichard Henderson      */
129543b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
1296ee8c7f9fSRichard Henderson     return true;
1297ee8c7f9fSRichard Henderson }
1298ee8c7f9fSRichard Henderson 
1299e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1300e6cb0354SRichard Henderson {
1301e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1302e6cb0354SRichard Henderson         return true;
1303e6cb0354SRichard Henderson     }
13042a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "rts")) {
13052a7567a2SRichard Henderson         return true;
13062a7567a2SRichard Henderson     }
13072a7567a2SRichard Henderson 
1308e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1309e6cb0354SRichard Henderson     setup_dslot(dc, true);
1310e6cb0354SRichard Henderson 
1311e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1312e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1313e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1314e6cb0354SRichard Henderson     return true;
1315e6cb0354SRichard Henderson }
1316e6cb0354SRichard Henderson 
1317e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1318e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1319e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1320e6cb0354SRichard Henderson 
1321e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1322e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1323e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1324e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1325e6cb0354SRichard Henderson 
132620800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
132720800179SRichard Henderson {
132820800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
13294b893631SRichard Henderson     if (dc->cfg->opcode_0_illegal) {
133020800179SRichard Henderson         trap_illegal(dc, true);
133120800179SRichard Henderson         return true;
133220800179SRichard Henderson     }
133320800179SRichard Henderson     /*
133420800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
133520800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
133620800179SRichard Henderson      */
133720800179SRichard Henderson     return false;
1338fcf5ef2aSThomas Huth }
1339fcf5ef2aSThomas Huth 
13401074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1341fcf5ef2aSThomas Huth {
13421074c0fbSRichard Henderson     TCGv_i32 t;
13431074c0fbSRichard Henderson 
13441074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
13451074c0fbSRichard Henderson     t = tcg_temp_new_i32();
13461074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13471074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
13481074c0fbSRichard Henderson     tcg_temp_free_i32(t);
1349fcf5ef2aSThomas Huth }
1350fcf5ef2aSThomas Huth 
1351536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1352536e340fSRichard Henderson {
1353536e340fSRichard Henderson     uint32_t imm = arg->imm;
1354536e340fSRichard Henderson 
1355536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1356536e340fSRichard Henderson         return true;
1357536e340fSRichard Henderson     }
1358536e340fSRichard Henderson 
1359536e340fSRichard Henderson     if (arg->rd) {
1360536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1361536e340fSRichard Henderson     }
1362536e340fSRichard Henderson 
1363536e340fSRichard Henderson     /*
1364536e340fSRichard Henderson      * Handle the carry bit separately.
1365536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1366536e340fSRichard Henderson      */
1367536e340fSRichard Henderson     if (imm & MSR_C) {
1368536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1369536e340fSRichard Henderson     }
1370536e340fSRichard Henderson 
1371536e340fSRichard Henderson     /*
1372536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1373536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1374536e340fSRichard Henderson      */
1375536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1376536e340fSRichard Henderson 
1377536e340fSRichard Henderson     if (imm != 0) {
1378536e340fSRichard Henderson         if (set) {
1379536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1380536e340fSRichard Henderson         } else {
1381536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1382536e340fSRichard Henderson         }
138343b34134SRichard Henderson         dc->base.is_jmp = DISAS_EXIT_NEXT;
1384536e340fSRichard Henderson     }
1385536e340fSRichard Henderson     return true;
1386536e340fSRichard Henderson }
1387536e340fSRichard Henderson 
1388536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1389536e340fSRichard Henderson {
1390536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1391536e340fSRichard Henderson }
1392536e340fSRichard Henderson 
1393536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1394536e340fSRichard Henderson {
1395536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1396536e340fSRichard Henderson }
1397536e340fSRichard Henderson 
13989df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
1399fcf5ef2aSThomas Huth {
14009df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
14019df297a2SRichard Henderson         return true;
1402f0f7e7f7SEdgar E. Iglesias     }
1403f0f7e7f7SEdgar E. Iglesias 
14049df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
14059df297a2SRichard Henderson     g_assert_not_reached();
14069df297a2SRichard Henderson #else
14079df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
14089df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
14099df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
14109df297a2SRichard Henderson         return true;
14112023e9a3SEdgar E. Iglesias     }
1412fcf5ef2aSThomas Huth 
14139df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
14149df297a2SRichard Henderson     switch (arg->rs) {
1415aa28e6d4SRichard Henderson     case SR_MSR:
141643b34134SRichard Henderson         /* Install MSR_C.  */
141743b34134SRichard Henderson         tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
141843b34134SRichard Henderson         /*
141943b34134SRichard Henderson          * Clear MSR_C and MSR_CC;
142043b34134SRichard Henderson          * MSR_PVR is not writable, and is always clear.
142143b34134SRichard Henderson          */
142243b34134SRichard Henderson         tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
1423fcf5ef2aSThomas Huth         break;
14249df297a2SRichard Henderson     case SR_FSR:
14259df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr));
14269df297a2SRichard Henderson         break;
14279df297a2SRichard Henderson     case 0x800:
14289df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr));
14299df297a2SRichard Henderson         break;
14309df297a2SRichard Henderson     case 0x802:
14319df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr));
14329df297a2SRichard Henderson         break;
14339df297a2SRichard Henderson 
14349df297a2SRichard Henderson     case 0x1000: /* PID */
14359df297a2SRichard Henderson     case 0x1001: /* ZPR */
14369df297a2SRichard Henderson     case 0x1002: /* TLBX */
14379df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14389df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14399df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14409df297a2SRichard Henderson         {
14419df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
14429df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
14439df297a2SRichard Henderson 
14449df297a2SRichard Henderson             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src);
14459df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
14469df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
14479df297a2SRichard Henderson         }
14489df297a2SRichard Henderson         break;
14499df297a2SRichard Henderson 
14509df297a2SRichard Henderson     default:
14519df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14529df297a2SRichard Henderson         return true;
14539df297a2SRichard Henderson     }
145443b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
14559df297a2SRichard Henderson     return true;
14569df297a2SRichard Henderson #endif
14579df297a2SRichard Henderson }
14589df297a2SRichard Henderson 
14599df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14609df297a2SRichard Henderson {
14619df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
14629df297a2SRichard Henderson 
14639df297a2SRichard Henderson     if (arg->e) {
14649df297a2SRichard Henderson         switch (arg->rs) {
1465351527b7SEdgar E. Iglesias         case SR_EAR:
1466dbdb77c4SRichard Henderson             {
1467dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
14689df297a2SRichard Henderson                 tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
14699df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1470dbdb77c4SRichard Henderson                 tcg_temp_free_i64(t64);
1471dbdb77c4SRichard Henderson             }
14729df297a2SRichard Henderson             return true;
14739df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14749df297a2SRichard Henderson         case 0x1003: /* TLBLO */
14759df297a2SRichard Henderson             /* Handled below. */
1476aa28e6d4SRichard Henderson             break;
14779df297a2SRichard Henderson #endif
14789df297a2SRichard Henderson         case 0x2006 ... 0x2009:
14799df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
14809df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
14819df297a2SRichard Henderson             return true;
1482fcf5ef2aSThomas Huth         default:
14839df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
14849df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
14859df297a2SRichard Henderson             return true;
1486fcf5ef2aSThomas Huth         }
14879df297a2SRichard Henderson     }
14889df297a2SRichard Henderson 
14899df297a2SRichard Henderson     switch (arg->rs) {
1490aa28e6d4SRichard Henderson     case SR_PC:
14919df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
1492fcf5ef2aSThomas Huth         break;
1493aa28e6d4SRichard Henderson     case SR_MSR:
14949df297a2SRichard Henderson         msr_read(dc, dest);
1495fcf5ef2aSThomas Huth         break;
1496351527b7SEdgar E. Iglesias     case SR_EAR:
1497dbdb77c4SRichard Henderson         {
1498dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1499dbdb77c4SRichard Henderson             tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
15009df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1501dbdb77c4SRichard Henderson             tcg_temp_free_i64(t64);
1502a1b48e3aSEdgar E. Iglesias         }
1503aa28e6d4SRichard Henderson         break;
1504351527b7SEdgar E. Iglesias     case SR_ESR:
15059df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr));
1506aa28e6d4SRichard Henderson         break;
1507351527b7SEdgar E. Iglesias     case SR_FSR:
15089df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr));
1509aa28e6d4SRichard Henderson         break;
1510351527b7SEdgar E. Iglesias     case SR_BTR:
15119df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr));
1512aa28e6d4SRichard Henderson         break;
15137cdae31dSTong Ho     case SR_EDR:
15149df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr));
1515fcf5ef2aSThomas Huth         break;
1516fcf5ef2aSThomas Huth     case 0x800:
15179df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr));
1518fcf5ef2aSThomas Huth         break;
1519fcf5ef2aSThomas Huth     case 0x802:
15209df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr));
1521fcf5ef2aSThomas Huth         break;
15229df297a2SRichard Henderson 
15239df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
15249df297a2SRichard Henderson     case 0x1000: /* PID */
15259df297a2SRichard Henderson     case 0x1001: /* ZPR */
15269df297a2SRichard Henderson     case 0x1002: /* TLBX */
15279df297a2SRichard Henderson     case 0x1003: /* TLBLO */
15289df297a2SRichard Henderson     case 0x1004: /* TLBHI */
15299df297a2SRichard Henderson     case 0x1005: /* TLBSX */
15309df297a2SRichard Henderson         {
15319df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
15329df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
15339df297a2SRichard Henderson 
15349df297a2SRichard Henderson             gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg);
15359df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
15369df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
15379df297a2SRichard Henderson         }
15389df297a2SRichard Henderson         break;
15399df297a2SRichard Henderson #endif
15409df297a2SRichard Henderson 
1541351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
15429df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env,
1543a4bcfc33SRichard Henderson                        offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1544a4bcfc33SRichard Henderson                        - offsetof(MicroBlazeCPU, env));
1545fcf5ef2aSThomas Huth         break;
1546fcf5ef2aSThomas Huth     default:
15479df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1548fcf5ef2aSThomas Huth         break;
1549fcf5ef2aSThomas Huth     }
15509df297a2SRichard Henderson     return true;
1551fcf5ef2aSThomas Huth }
1552fcf5ef2aSThomas Huth 
15533fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
1554fcf5ef2aSThomas Huth {
15553fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1556fcf5ef2aSThomas Huth 
15573fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15583fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15593fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15603fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15613fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15623fb394fdSRichard Henderson 
15633fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1564fcf5ef2aSThomas Huth }
1565fcf5ef2aSThomas Huth 
15663fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
1567fcf5ef2aSThomas Huth {
15683fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1569fcf5ef2aSThomas Huth 
15703fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15713fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15723fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15733fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15743fb394fdSRichard Henderson 
15753fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1576fcf5ef2aSThomas Huth }
1577fcf5ef2aSThomas Huth 
15783fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
1579fcf5ef2aSThomas Huth {
15803fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1581fcf5ef2aSThomas Huth 
15823fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15833fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15843fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15853fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15863fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1587fcf5ef2aSThomas Huth 
15883fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1589fcf5ef2aSThomas Huth }
1590fcf5ef2aSThomas Huth 
1591fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
159252065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1593fcf5ef2aSThomas Huth {
1594fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1595fcf5ef2aSThomas Huth 
1596bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
159752065d8fSRichard Henderson         return true;
1598fcf5ef2aSThomas Huth     }
1599fcf5ef2aSThomas Huth 
1600cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
160152065d8fSRichard Henderson     if (rb) {
160252065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1603fcf5ef2aSThomas Huth     } else {
160452065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
1605fcf5ef2aSThomas Huth     }
1606fcf5ef2aSThomas Huth 
1607cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
160852065d8fSRichard Henderson     gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
1609cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1610cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
161152065d8fSRichard Henderson     return true;
161252065d8fSRichard Henderson }
161352065d8fSRichard Henderson 
161452065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
161552065d8fSRichard Henderson {
161652065d8fSRichard Henderson     return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
161752065d8fSRichard Henderson }
161852065d8fSRichard Henderson 
161952065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
162052065d8fSRichard Henderson {
162152065d8fSRichard Henderson     return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
162252065d8fSRichard Henderson }
162352065d8fSRichard Henderson 
162452065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
162552065d8fSRichard Henderson {
162652065d8fSRichard Henderson     TCGv_i32 t_id, t_ctrl;
162752065d8fSRichard Henderson 
162852065d8fSRichard Henderson     if (trap_userspace(dc, true)) {
162952065d8fSRichard Henderson         return true;
163052065d8fSRichard Henderson     }
163152065d8fSRichard Henderson 
163252065d8fSRichard Henderson     t_id = tcg_temp_new_i32();
163352065d8fSRichard Henderson     if (rb) {
163452065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
163552065d8fSRichard Henderson     } else {
163652065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
163752065d8fSRichard Henderson     }
163852065d8fSRichard Henderson 
163952065d8fSRichard Henderson     t_ctrl = tcg_const_i32(ctrl);
164052065d8fSRichard Henderson     gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
164152065d8fSRichard Henderson     tcg_temp_free_i32(t_id);
164252065d8fSRichard Henderson     tcg_temp_free_i32(t_ctrl);
164352065d8fSRichard Henderson     return true;
164452065d8fSRichard Henderson }
164552065d8fSRichard Henderson 
164652065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
164752065d8fSRichard Henderson {
164852065d8fSRichard Henderson     return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
164952065d8fSRichard Henderson }
165052065d8fSRichard Henderson 
165152065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
165252065d8fSRichard Henderson {
165352065d8fSRichard Henderson     return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1654fcf5ef2aSThomas Huth }
1655fcf5ef2aSThomas Huth 
1656372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1657fcf5ef2aSThomas Huth {
1658372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1659372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1660372122e3SRichard Henderson     int bound;
1661fcf5ef2aSThomas Huth 
16624b893631SRichard Henderson     dc->cfg = &cpu->cfg;
1663683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1664d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
166520800179SRichard Henderson     dc->r0 = NULL;
166620800179SRichard Henderson     dc->r0_set = false;
1667287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
1668b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1669b9c58aabSRichard Henderson     dc->jmp_dest = -1;
1670fcf5ef2aSThomas Huth 
1671372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1672372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1673fcf5ef2aSThomas Huth }
1674fcf5ef2aSThomas Huth 
1675372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1676fcf5ef2aSThomas Huth {
1677fcf5ef2aSThomas Huth }
1678fcf5ef2aSThomas Huth 
1679372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1680372122e3SRichard Henderson {
1681683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1682683a247eSRichard Henderson 
1683683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1684683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1685372122e3SRichard Henderson }
1686fcf5ef2aSThomas Huth 
1687372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1688372122e3SRichard Henderson {
1689372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1690372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
169144d1432bSRichard Henderson     uint32_t ir;
1692372122e3SRichard Henderson 
1693372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1694372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1695372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1696372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1697fcf5ef2aSThomas Huth     }
1698fcf5ef2aSThomas Huth 
16996f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
17006f9642d7SRichard Henderson 
170144d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
170244d1432bSRichard Henderson     if (!decode(dc, ir)) {
1703921afa9dSRichard Henderson         trap_illegal(dc, true);
170444d1432bSRichard Henderson     }
170520800179SRichard Henderson 
170620800179SRichard Henderson     if (dc->r0) {
170720800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
170820800179SRichard Henderson         dc->r0 = NULL;
170920800179SRichard Henderson         dc->r0_set = false;
171020800179SRichard Henderson     }
171120800179SRichard Henderson 
17126f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
17136f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1714d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1715372122e3SRichard Henderson     }
17166f9642d7SRichard Henderson 
17171e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
17186f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1719d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1720fcf5ef2aSThomas Huth 
1721b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
17223d35bcc2SRichard Henderson         /*
17233d35bcc2SRichard Henderson          * Finish any return-from branch.
17243d35bcc2SRichard Henderson          */
17253c745866SRichard Henderson         uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
17263c745866SRichard Henderson         if (unlikely(rt_ibe != 0)) {
17273c745866SRichard Henderson             dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
17283c745866SRichard Henderson             if (rt_ibe & DRTI_FLAG) {
1729fcf5ef2aSThomas Huth                 do_rti(dc);
17303c745866SRichard Henderson             } else if (rt_ibe & DRTB_FLAG) {
1731fcf5ef2aSThomas Huth                 do_rtb(dc);
17323c745866SRichard Henderson             } else {
1733fcf5ef2aSThomas Huth                 do_rte(dc);
1734372122e3SRichard Henderson             }
17353c745866SRichard Henderson         }
17363d35bcc2SRichard Henderson 
17373d35bcc2SRichard Henderson         /* Complete the branch, ending the TB. */
17383d35bcc2SRichard Henderson         switch (dc->base.is_jmp) {
17393d35bcc2SRichard Henderson         case DISAS_NORETURN:
17403d35bcc2SRichard Henderson             /*
17413d35bcc2SRichard Henderson              * E.g. illegal insn in a delay slot.  We've already exited
17423d35bcc2SRichard Henderson              * and will handle D_FLAG in mb_cpu_do_interrupt.
17433d35bcc2SRichard Henderson              */
17443d35bcc2SRichard Henderson             break;
17453d35bcc2SRichard Henderson         case DISAS_NEXT:
17463c745866SRichard Henderson             /*
17473c745866SRichard Henderson              * Normal insn a delay slot.
17483c745866SRichard Henderson              * However, the return-from-exception type insns should
17493c745866SRichard Henderson              * return to the main loop, as they have adjusted MSR.
17503c745866SRichard Henderson              */
17513c745866SRichard Henderson             dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
17523d35bcc2SRichard Henderson             break;
17533d35bcc2SRichard Henderson         case DISAS_EXIT_NEXT:
17543d35bcc2SRichard Henderson             /*
17553d35bcc2SRichard Henderson              * E.g. mts insn in a delay slot.  Continue with btarget,
17563d35bcc2SRichard Henderson              * but still return to the main loop.
17573d35bcc2SRichard Henderson              */
17583d35bcc2SRichard Henderson             dc->base.is_jmp = DISAS_EXIT_JUMP;
17593d35bcc2SRichard Henderson             break;
17603d35bcc2SRichard Henderson         default:
17613d35bcc2SRichard Henderson             g_assert_not_reached();
17623d35bcc2SRichard Henderson         }
1763372122e3SRichard Henderson     }
1764372122e3SRichard Henderson }
1765372122e3SRichard Henderson 
1766372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1767372122e3SRichard Henderson {
1768372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1769372122e3SRichard Henderson 
1770372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1771372122e3SRichard Henderson         /* We have already exited the TB. */
1772372122e3SRichard Henderson         return;
1773372122e3SRichard Henderson     }
1774372122e3SRichard Henderson 
1775372122e3SRichard Henderson     t_sync_flags(dc);
1776372122e3SRichard Henderson 
1777372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1778372122e3SRichard Henderson     case DISAS_TOO_MANY:
1779372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1780372122e3SRichard Henderson         return;
1781372122e3SRichard Henderson 
178217e77796SRichard Henderson     case DISAS_EXIT:
1783f6278ca9SRichard Henderson         break;
1784f6278ca9SRichard Henderson     case DISAS_EXIT_NEXT:
1785f6278ca9SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1786f6278ca9SRichard Henderson         break;
1787f6278ca9SRichard Henderson     case DISAS_EXIT_JUMP:
1788f6278ca9SRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1789f6278ca9SRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1790f6278ca9SRichard Henderson         break;
1791372122e3SRichard Henderson 
1792372122e3SRichard Henderson     case DISAS_JUMP:
1793fbafb3a4SRichard Henderson         if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
1794b9c58aabSRichard Henderson             /* Direct jump. */
1795b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1796b9c58aabSRichard Henderson 
1797b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1798b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1799b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1800b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1801b9c58aabSRichard Henderson 
1802b9c58aabSRichard Henderson                 /*
1803b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1804b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1805b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1806b9c58aabSRichard Henderson                  */
1807b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1808b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1809b9c58aabSRichard Henderson 
1810b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1811b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1812b9c58aabSRichard Henderson                 gen_set_label(taken);
1813b9c58aabSRichard Henderson             }
1814b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1815b9c58aabSRichard Henderson             return;
1816b9c58aabSRichard Henderson         }
1817b9c58aabSRichard Henderson 
1818fbafb3a4SRichard Henderson         /* Indirect jump (or direct jump w/ goto_tb disabled) */
1819b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1820b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
18214059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
1822372122e3SRichard Henderson         return;
1823372122e3SRichard Henderson 
1824a2b80dbdSRichard Henderson     default:
1825a2b80dbdSRichard Henderson         g_assert_not_reached();
1826fcf5ef2aSThomas Huth     }
1827f6278ca9SRichard Henderson 
1828f6278ca9SRichard Henderson     /* Finish DISAS_EXIT_* */
1829f6278ca9SRichard Henderson     if (unlikely(cs->singlestep_enabled)) {
1830f6278ca9SRichard Henderson         gen_raise_exception(dc, EXCP_DEBUG);
1831f6278ca9SRichard Henderson     } else {
1832f6278ca9SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1833f6278ca9SRichard Henderson     }
1834fcf5ef2aSThomas Huth }
1835fcf5ef2aSThomas Huth 
1836*8eb806a7SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb,
1837*8eb806a7SRichard Henderson                             CPUState *cs, FILE *logfile)
1838372122e3SRichard Henderson {
1839*8eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(dcb->pc_first));
1840*8eb806a7SRichard Henderson     target_disas(logfile, cs, dcb->pc_first, dcb->tb->size);
1841fcf5ef2aSThomas Huth }
1842372122e3SRichard Henderson 
1843372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1844372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1845372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1846372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1847372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1848372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1849372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1850372122e3SRichard Henderson };
1851372122e3SRichard Henderson 
1852372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1853372122e3SRichard Henderson {
1854372122e3SRichard Henderson     DisasContext dc;
1855372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1856fcf5ef2aSThomas Huth }
1857fcf5ef2aSThomas Huth 
185890c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1859fcf5ef2aSThomas Huth {
1860fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1861fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
18620c3da918SRichard Henderson     uint32_t iflags;
1863fcf5ef2aSThomas Huth     int i;
1864fcf5ef2aSThomas Huth 
18650c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18660c3da918SRichard Henderson                  env->pc, env->msr,
18672e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18682e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18692e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18702e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18710c3da918SRichard Henderson 
18720c3da918SRichard Henderson     iflags = env->iflags;
18730c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18740c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18750c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18762ead1b18SJoe Komlodi     }
18770c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18780c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18790c3da918SRichard Henderson     }
18800c3da918SRichard Henderson     if (iflags & D_FLAG) {
1881b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18820c3da918SRichard Henderson     }
18830c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18840c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18850c3da918SRichard Henderson     }
18860c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18870c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18880c3da918SRichard Henderson     }
18890c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18900c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18910c3da918SRichard Henderson     }
18920c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18930c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18942ead1b18SJoe Komlodi     }
1895fcf5ef2aSThomas Huth 
18960c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
189719f27b6cSRichard Henderson                  "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
18980c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18990c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
19000c3da918SRichard Henderson 
19010c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
19020c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
19030c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
19040c3da918SRichard Henderson     }
19050c3da918SRichard Henderson     qemu_fprintf(f, "\n");
1906fcf5ef2aSThomas Huth }
1907fcf5ef2aSThomas Huth 
1908fcf5ef2aSThomas Huth void mb_tcg_init(void)
1909fcf5ef2aSThomas Huth {
1910480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1911480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1912fcf5ef2aSThomas Huth 
1913480d29a8SRichard Henderson     static const struct {
1914480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1915480d29a8SRichard Henderson     } i32s[] = {
1916e47c2231SRichard Henderson         /*
1917e47c2231SRichard Henderson          * Note that r0 is handled specially in reg_for_read
1918e47c2231SRichard Henderson          * and reg_for_write.  Nothing should touch cpu_R[0].
1919e47c2231SRichard Henderson          * Leave that element NULL, which will assert quickly
1920e47c2231SRichard Henderson          * inside the tcg generator functions.
1921e47c2231SRichard Henderson          */
1922e47c2231SRichard Henderson                R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1923480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1924480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1925480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1926480d29a8SRichard Henderson 
1927480d29a8SRichard Henderson         SP(pc),
1928480d29a8SRichard Henderson         SP(msr),
19291074c0fbSRichard Henderson         SP(msr_c),
1930480d29a8SRichard Henderson         SP(imm),
1931480d29a8SRichard Henderson         SP(iflags),
1932b9c58aabSRichard Henderson         SP(bvalue),
1933480d29a8SRichard Henderson         SP(btarget),
1934480d29a8SRichard Henderson         SP(res_val),
1935480d29a8SRichard Henderson     };
1936480d29a8SRichard Henderson 
1937480d29a8SRichard Henderson #undef R
1938480d29a8SRichard Henderson #undef SP
1939480d29a8SRichard Henderson 
1940480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1941480d29a8SRichard Henderson         *i32s[i].var =
1942480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1943fcf5ef2aSThomas Huth     }
194476e8187dSRichard Henderson 
1945480d29a8SRichard Henderson     cpu_res_addr =
1946480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1947fcf5ef2aSThomas Huth }
1948fcf5ef2aSThomas Huth 
1949fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1950fcf5ef2aSThomas Huth                           target_ulong *data)
1951fcf5ef2aSThomas Huth {
195276e8187dSRichard Henderson     env->pc = data[0];
1953683a247eSRichard Henderson     env->iflags = data[1];
1954fcf5ef2aSThomas Huth }
1955