xref: /openbmc/qemu/target/microblaze/translate.c (revision fbafb3a4d2fc90efdba05ec0d1f2ad7c4f68e9a5)
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 {
129d4705ae0SRichard Henderson     if (dc->base.singlestep_enabled) {
1300b46fa08SRichard Henderson         TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG);
1310b46fa08SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1320b46fa08SRichard Henderson         gen_helper_raise_exception(cpu_env, tmp);
1330b46fa08SRichard Henderson         tcg_temp_free_i32(tmp);
134725930c2SRichard Henderson     } else if (translator_use_goto_tb(&dc->base, dest)) {
135fcf5ef2aSThomas Huth         tcg_gen_goto_tb(n);
1360f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
137d4705ae0SRichard Henderson         tcg_gen_exit_tb(dc->base.tb, n);
138fcf5ef2aSThomas Huth     } else {
1390f96e96bSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dest);
1404059bd90SRichard Henderson         tcg_gen_lookup_and_goto_ptr();
141fcf5ef2aSThomas Huth     }
142d4705ae0SRichard Henderson     dc->base.is_jmp = DISAS_NORETURN;
143fcf5ef2aSThomas Huth }
144fcf5ef2aSThomas Huth 
145bdfc1e88SEdgar E. Iglesias /*
1469ba8cd45SEdgar E. Iglesias  * Returns true if the insn an illegal operation.
1479ba8cd45SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
1489ba8cd45SEdgar E. Iglesias  */
1499ba8cd45SEdgar E. Iglesias static bool trap_illegal(DisasContext *dc, bool cond)
1509ba8cd45SEdgar E. Iglesias {
1512c32179fSRichard Henderson     if (cond && (dc->tb_flags & MSR_EE)
1524b893631SRichard Henderson         && dc->cfg->illegal_opcode_exception) {
15341ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
1549ba8cd45SEdgar E. Iglesias     }
1559ba8cd45SEdgar E. Iglesias     return cond;
1569ba8cd45SEdgar E. Iglesias }
1579ba8cd45SEdgar E. Iglesias 
1589ba8cd45SEdgar E. Iglesias /*
159bdfc1e88SEdgar E. Iglesias  * Returns true if the insn is illegal in userspace.
160bdfc1e88SEdgar E. Iglesias  * If exceptions are enabled, an exception is raised.
161bdfc1e88SEdgar E. Iglesias  */
162bdfc1e88SEdgar E. Iglesias static bool trap_userspace(DisasContext *dc, bool cond)
163bdfc1e88SEdgar E. Iglesias {
164287b1defSRichard Henderson     bool cond_user = cond && dc->mem_index == MMU_USER_IDX;
165bdfc1e88SEdgar E. Iglesias 
1662c32179fSRichard Henderson     if (cond_user && (dc->tb_flags & MSR_EE)) {
16741ba37c4SRichard Henderson         gen_raise_hw_excp(dc, ESR_EC_PRIVINSN);
168bdfc1e88SEdgar E. Iglesias     }
169bdfc1e88SEdgar E. Iglesias     return cond_user;
170bdfc1e88SEdgar E. Iglesias }
171bdfc1e88SEdgar E. Iglesias 
1722a7567a2SRichard Henderson /*
1732a7567a2SRichard Henderson  * Return true, and log an error, if the current insn is
1742a7567a2SRichard Henderson  * within a delay slot.
1752a7567a2SRichard Henderson  */
1762a7567a2SRichard Henderson static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
1772a7567a2SRichard Henderson {
1782a7567a2SRichard Henderson     if (dc->tb_flags & D_FLAG) {
1792a7567a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
1802a7567a2SRichard Henderson                       "Invalid insn in delay slot: %s at %08x\n",
1812a7567a2SRichard Henderson                       insn_type, (uint32_t)dc->base.pc_next);
1822a7567a2SRichard Henderson         return true;
1832a7567a2SRichard Henderson     }
1842a7567a2SRichard Henderson     return false;
1852a7567a2SRichard Henderson }
1862a7567a2SRichard Henderson 
18720800179SRichard Henderson static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
188fcf5ef2aSThomas Huth {
18920800179SRichard Henderson     if (likely(reg != 0)) {
19020800179SRichard Henderson         return cpu_R[reg];
191fcf5ef2aSThomas Huth     }
19220800179SRichard Henderson     if (!dc->r0_set) {
19320800179SRichard Henderson         if (dc->r0 == NULL) {
19420800179SRichard Henderson             dc->r0 = tcg_temp_new_i32();
195fcf5ef2aSThomas Huth         }
19620800179SRichard Henderson         tcg_gen_movi_i32(dc->r0, 0);
19720800179SRichard Henderson         dc->r0_set = true;
19820800179SRichard Henderson     }
19920800179SRichard Henderson     return dc->r0;
200fcf5ef2aSThomas Huth }
201fcf5ef2aSThomas Huth 
20220800179SRichard Henderson static TCGv_i32 reg_for_write(DisasContext *dc, int reg)
20320800179SRichard Henderson {
20420800179SRichard Henderson     if (likely(reg != 0)) {
20520800179SRichard Henderson         return cpu_R[reg];
20620800179SRichard Henderson     }
20720800179SRichard Henderson     if (dc->r0 == NULL) {
20820800179SRichard Henderson         dc->r0 = tcg_temp_new_i32();
20920800179SRichard Henderson     }
21020800179SRichard Henderson     return dc->r0;
211fcf5ef2aSThomas Huth }
212fcf5ef2aSThomas Huth 
21320800179SRichard Henderson static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects,
21420800179SRichard Henderson                      void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
21520800179SRichard Henderson {
21620800179SRichard Henderson     TCGv_i32 rd, ra, rb;
21720800179SRichard Henderson 
21820800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
21920800179SRichard Henderson         return true;
220fcf5ef2aSThomas Huth     }
22120800179SRichard Henderson 
22220800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
22320800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
22420800179SRichard Henderson     rb = reg_for_read(dc, arg->rb);
22520800179SRichard Henderson     fn(rd, ra, rb);
22620800179SRichard Henderson     return true;
22720800179SRichard Henderson }
22820800179SRichard Henderson 
22939cf3864SRichard Henderson static bool do_typea0(DisasContext *dc, arg_typea0 *arg, bool side_effects,
23039cf3864SRichard Henderson                       void (*fn)(TCGv_i32, TCGv_i32))
23139cf3864SRichard Henderson {
23239cf3864SRichard Henderson     TCGv_i32 rd, ra;
23339cf3864SRichard Henderson 
23439cf3864SRichard Henderson     if (arg->rd == 0 && !side_effects) {
23539cf3864SRichard Henderson         return true;
23639cf3864SRichard Henderson     }
23739cf3864SRichard Henderson 
23839cf3864SRichard Henderson     rd = reg_for_write(dc, arg->rd);
23939cf3864SRichard Henderson     ra = reg_for_read(dc, arg->ra);
24039cf3864SRichard Henderson     fn(rd, ra);
24139cf3864SRichard Henderson     return true;
24239cf3864SRichard Henderson }
24339cf3864SRichard Henderson 
24420800179SRichard Henderson static bool do_typeb_imm(DisasContext *dc, arg_typeb *arg, bool side_effects,
24520800179SRichard Henderson                          void (*fni)(TCGv_i32, TCGv_i32, int32_t))
24620800179SRichard Henderson {
24720800179SRichard Henderson     TCGv_i32 rd, ra;
24820800179SRichard Henderson 
24920800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
25020800179SRichard Henderson         return true;
25120800179SRichard Henderson     }
25220800179SRichard Henderson 
25320800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
25420800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
25520800179SRichard Henderson     fni(rd, ra, arg->imm);
25620800179SRichard Henderson     return true;
25720800179SRichard Henderson }
25820800179SRichard Henderson 
25920800179SRichard Henderson static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
26020800179SRichard Henderson                          void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32))
26120800179SRichard Henderson {
26220800179SRichard Henderson     TCGv_i32 rd, ra, imm;
26320800179SRichard Henderson 
26420800179SRichard Henderson     if (arg->rd == 0 && !side_effects) {
26520800179SRichard Henderson         return true;
26620800179SRichard Henderson     }
26720800179SRichard Henderson 
26820800179SRichard Henderson     rd = reg_for_write(dc, arg->rd);
26920800179SRichard Henderson     ra = reg_for_read(dc, arg->ra);
27020800179SRichard Henderson     imm = tcg_const_i32(arg->imm);
27120800179SRichard Henderson 
27220800179SRichard Henderson     fn(rd, ra, imm);
27320800179SRichard Henderson 
27420800179SRichard Henderson     tcg_temp_free_i32(imm);
27520800179SRichard Henderson     return true;
27620800179SRichard Henderson }
27720800179SRichard Henderson 
27820800179SRichard Henderson #define DO_TYPEA(NAME, SE, FN) \
27920800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
28020800179SRichard Henderson     { return do_typea(dc, a, SE, FN); }
28120800179SRichard Henderson 
282607f5767SRichard Henderson #define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
283607f5767SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
2844b893631SRichard Henderson     { return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
285607f5767SRichard Henderson 
28639cf3864SRichard Henderson #define DO_TYPEA0(NAME, SE, FN) \
28739cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
28839cf3864SRichard Henderson     { return do_typea0(dc, a, SE, FN); }
28939cf3864SRichard Henderson 
29039cf3864SRichard Henderson #define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
29139cf3864SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
2924b893631SRichard Henderson     { return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
29339cf3864SRichard Henderson 
29420800179SRichard Henderson #define DO_TYPEBI(NAME, SE, FNI) \
29520800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
29620800179SRichard Henderson     { return do_typeb_imm(dc, a, SE, FNI); }
29720800179SRichard Henderson 
29897955cebSRichard Henderson #define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
29997955cebSRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
3004b893631SRichard Henderson     { return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
30197955cebSRichard Henderson 
30220800179SRichard Henderson #define DO_TYPEBV(NAME, SE, FN) \
30320800179SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
30420800179SRichard Henderson     { return do_typeb_val(dc, a, SE, FN); }
30520800179SRichard Henderson 
306d5aead3dSRichard Henderson #define ENV_WRAPPER2(NAME, HELPER) \
307d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina) \
308d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina); }
309d5aead3dSRichard Henderson 
310d5aead3dSRichard Henderson #define ENV_WRAPPER3(NAME, HELPER) \
311d5aead3dSRichard Henderson     static void NAME(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) \
312d5aead3dSRichard Henderson     { HELPER(out, cpu_env, ina, inb); }
313d5aead3dSRichard Henderson 
31420800179SRichard Henderson /* No input carry, but output carry. */
31520800179SRichard Henderson static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
31620800179SRichard Henderson {
31720800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
31820800179SRichard Henderson 
31920800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, ina, zero, inb, zero);
32020800179SRichard Henderson 
32120800179SRichard Henderson     tcg_temp_free_i32(zero);
32220800179SRichard Henderson }
32320800179SRichard Henderson 
32420800179SRichard Henderson /* Input and output carry. */
32520800179SRichard Henderson static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
32620800179SRichard Henderson {
32720800179SRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
32820800179SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
32920800179SRichard Henderson 
33020800179SRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero);
33120800179SRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
33220800179SRichard Henderson 
33320800179SRichard Henderson     tcg_temp_free_i32(tmp);
33420800179SRichard Henderson     tcg_temp_free_i32(zero);
33520800179SRichard Henderson }
33620800179SRichard Henderson 
33720800179SRichard Henderson /* Input carry, but no output carry. */
33820800179SRichard Henderson static void gen_addkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
33920800179SRichard Henderson {
34020800179SRichard Henderson     tcg_gen_add_i32(out, ina, inb);
34120800179SRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
34220800179SRichard Henderson }
34320800179SRichard Henderson 
34420800179SRichard Henderson DO_TYPEA(add, true, gen_add)
34520800179SRichard Henderson DO_TYPEA(addc, true, gen_addc)
34620800179SRichard Henderson DO_TYPEA(addk, false, tcg_gen_add_i32)
34720800179SRichard Henderson DO_TYPEA(addkc, true, gen_addkc)
34820800179SRichard Henderson 
34920800179SRichard Henderson DO_TYPEBV(addi, true, gen_add)
35020800179SRichard Henderson DO_TYPEBV(addic, true, gen_addc)
35120800179SRichard Henderson DO_TYPEBI(addik, false, tcg_gen_addi_i32)
35220800179SRichard Henderson DO_TYPEBV(addikc, true, gen_addkc)
35320800179SRichard Henderson 
354cb0a0a4cSRichard Henderson static void gen_andni(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
355cb0a0a4cSRichard Henderson {
356cb0a0a4cSRichard Henderson     tcg_gen_andi_i32(out, ina, ~imm);
357cb0a0a4cSRichard Henderson }
358cb0a0a4cSRichard Henderson 
359cb0a0a4cSRichard Henderson DO_TYPEA(and, false, tcg_gen_and_i32)
360cb0a0a4cSRichard Henderson DO_TYPEBI(andi, false, tcg_gen_andi_i32)
361cb0a0a4cSRichard Henderson DO_TYPEA(andn, false, tcg_gen_andc_i32)
362cb0a0a4cSRichard Henderson DO_TYPEBI(andni, false, gen_andni)
363cb0a0a4cSRichard Henderson 
364081d8e02SRichard Henderson static void gen_bsra(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
365081d8e02SRichard Henderson {
366081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
367081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
368081d8e02SRichard Henderson     tcg_gen_sar_i32(out, ina, tmp);
369081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
370081d8e02SRichard Henderson }
371081d8e02SRichard Henderson 
372081d8e02SRichard Henderson static void gen_bsrl(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
373081d8e02SRichard Henderson {
374081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
375081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
376081d8e02SRichard Henderson     tcg_gen_shr_i32(out, ina, tmp);
377081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
378081d8e02SRichard Henderson }
379081d8e02SRichard Henderson 
380081d8e02SRichard Henderson static void gen_bsll(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
381081d8e02SRichard Henderson {
382081d8e02SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
383081d8e02SRichard Henderson     tcg_gen_andi_i32(tmp, inb, 31);
384081d8e02SRichard Henderson     tcg_gen_shl_i32(out, ina, tmp);
385081d8e02SRichard Henderson     tcg_temp_free_i32(tmp);
386081d8e02SRichard Henderson }
387081d8e02SRichard Henderson 
388081d8e02SRichard Henderson static void gen_bsefi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
389081d8e02SRichard Henderson {
390081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
391081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
392081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
393081d8e02SRichard Henderson 
394081d8e02SRichard Henderson     if (imm_w + imm_s > 32 || imm_w == 0) {
395081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
396081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsefi: Bad input w=%d s=%d\n",
397081d8e02SRichard Henderson                       imm_w, imm_s);
398081d8e02SRichard Henderson     } else {
399081d8e02SRichard Henderson         tcg_gen_extract_i32(out, ina, imm_s, imm_w);
400081d8e02SRichard Henderson     }
401081d8e02SRichard Henderson }
402081d8e02SRichard Henderson 
403081d8e02SRichard Henderson static void gen_bsifi(TCGv_i32 out, TCGv_i32 ina, int32_t imm)
404081d8e02SRichard Henderson {
405081d8e02SRichard Henderson     /* Note that decodetree has extracted and reassembled imm_w/imm_s. */
406081d8e02SRichard Henderson     int imm_w = extract32(imm, 5, 5);
407081d8e02SRichard Henderson     int imm_s = extract32(imm, 0, 5);
408081d8e02SRichard Henderson     int width = imm_w - imm_s + 1;
409081d8e02SRichard Henderson 
410081d8e02SRichard Henderson     if (imm_w < imm_s) {
411081d8e02SRichard Henderson         /* These inputs have an undefined behavior.  */
412081d8e02SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "bsifi: Bad input w=%d s=%d\n",
413081d8e02SRichard Henderson                       imm_w, imm_s);
414081d8e02SRichard Henderson     } else {
415081d8e02SRichard Henderson         tcg_gen_deposit_i32(out, out, ina, imm_s, width);
416081d8e02SRichard Henderson     }
417081d8e02SRichard Henderson }
418081d8e02SRichard Henderson 
419081d8e02SRichard Henderson DO_TYPEA_CFG(bsra, use_barrel, false, gen_bsra)
420081d8e02SRichard Henderson DO_TYPEA_CFG(bsrl, use_barrel, false, gen_bsrl)
421081d8e02SRichard Henderson DO_TYPEA_CFG(bsll, use_barrel, false, gen_bsll)
422081d8e02SRichard Henderson 
423081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrai, use_barrel, false, tcg_gen_sari_i32)
424081d8e02SRichard Henderson DO_TYPEBI_CFG(bsrli, use_barrel, false, tcg_gen_shri_i32)
425081d8e02SRichard Henderson DO_TYPEBI_CFG(bslli, use_barrel, false, tcg_gen_shli_i32)
426081d8e02SRichard Henderson 
427081d8e02SRichard Henderson DO_TYPEBI_CFG(bsefi, use_barrel, false, gen_bsefi)
428081d8e02SRichard Henderson DO_TYPEBI_CFG(bsifi, use_barrel, false, gen_bsifi)
429081d8e02SRichard Henderson 
43039cf3864SRichard Henderson static void gen_clz(TCGv_i32 out, TCGv_i32 ina)
43139cf3864SRichard Henderson {
43239cf3864SRichard Henderson     tcg_gen_clzi_i32(out, ina, 32);
43339cf3864SRichard Henderson }
43439cf3864SRichard Henderson 
43539cf3864SRichard Henderson DO_TYPEA0_CFG(clz, use_pcmp_instr, false, gen_clz)
43639cf3864SRichard Henderson 
43758b48b63SRichard Henderson static void gen_cmp(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
43858b48b63SRichard Henderson {
43958b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
44058b48b63SRichard Henderson 
44158b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LT, lt, inb, ina);
44258b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
44358b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
44458b48b63SRichard Henderson     tcg_temp_free_i32(lt);
44558b48b63SRichard Henderson }
44658b48b63SRichard Henderson 
44758b48b63SRichard Henderson static void gen_cmpu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
44858b48b63SRichard Henderson {
44958b48b63SRichard Henderson     TCGv_i32 lt = tcg_temp_new_i32();
45058b48b63SRichard Henderson 
45158b48b63SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_LTU, lt, inb, ina);
45258b48b63SRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
45358b48b63SRichard Henderson     tcg_gen_deposit_i32(out, out, lt, 31, 1);
45458b48b63SRichard Henderson     tcg_temp_free_i32(lt);
45558b48b63SRichard Henderson }
45658b48b63SRichard Henderson 
45758b48b63SRichard Henderson DO_TYPEA(cmp, false, gen_cmp)
45858b48b63SRichard Henderson DO_TYPEA(cmpu, false, gen_cmpu)
459a2b0b90eSRichard Henderson 
460d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fadd, gen_helper_fadd)
461d5aead3dSRichard Henderson ENV_WRAPPER3(gen_frsub, gen_helper_frsub)
462d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fmul, gen_helper_fmul)
463d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fdiv, gen_helper_fdiv)
464d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_un, gen_helper_fcmp_un)
465d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_lt, gen_helper_fcmp_lt)
466d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_eq, gen_helper_fcmp_eq)
467d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_le, gen_helper_fcmp_le)
468d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_gt, gen_helper_fcmp_gt)
469d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ne, gen_helper_fcmp_ne)
470d5aead3dSRichard Henderson ENV_WRAPPER3(gen_fcmp_ge, gen_helper_fcmp_ge)
471d5aead3dSRichard Henderson 
472d5aead3dSRichard Henderson DO_TYPEA_CFG(fadd, use_fpu, true, gen_fadd)
473d5aead3dSRichard Henderson DO_TYPEA_CFG(frsub, use_fpu, true, gen_frsub)
474d5aead3dSRichard Henderson DO_TYPEA_CFG(fmul, use_fpu, true, gen_fmul)
475d5aead3dSRichard Henderson DO_TYPEA_CFG(fdiv, use_fpu, true, gen_fdiv)
476d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_un, use_fpu, true, gen_fcmp_un)
477d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_lt, use_fpu, true, gen_fcmp_lt)
478d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_eq, use_fpu, true, gen_fcmp_eq)
479d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_le, use_fpu, true, gen_fcmp_le)
480d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_gt, use_fpu, true, gen_fcmp_gt)
481d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ne, use_fpu, true, gen_fcmp_ne)
482d5aead3dSRichard Henderson DO_TYPEA_CFG(fcmp_ge, use_fpu, true, gen_fcmp_ge)
483d5aead3dSRichard Henderson 
484d5aead3dSRichard Henderson ENV_WRAPPER2(gen_flt, gen_helper_flt)
485d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fint, gen_helper_fint)
486d5aead3dSRichard Henderson ENV_WRAPPER2(gen_fsqrt, gen_helper_fsqrt)
487d5aead3dSRichard Henderson 
488d5aead3dSRichard Henderson DO_TYPEA0_CFG(flt, use_fpu >= 2, true, gen_flt)
489d5aead3dSRichard Henderson DO_TYPEA0_CFG(fint, use_fpu >= 2, true, gen_fint)
490d5aead3dSRichard Henderson DO_TYPEA0_CFG(fsqrt, use_fpu >= 2, true, gen_fsqrt)
491d5aead3dSRichard Henderson 
492d5aead3dSRichard Henderson /* Does not use ENV_WRAPPER3, because arguments are swapped as well. */
493b1354342SRichard Henderson static void gen_idiv(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
494b1354342SRichard Henderson {
495b1354342SRichard Henderson     gen_helper_divs(out, cpu_env, inb, ina);
496b1354342SRichard Henderson }
497b1354342SRichard Henderson 
498b1354342SRichard Henderson static void gen_idivu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
499b1354342SRichard Henderson {
500b1354342SRichard Henderson     gen_helper_divu(out, cpu_env, inb, ina);
501b1354342SRichard Henderson }
502b1354342SRichard Henderson 
503b1354342SRichard Henderson DO_TYPEA_CFG(idiv, use_div, true, gen_idiv)
504b1354342SRichard Henderson DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
505b1354342SRichard Henderson 
506e64b2e5cSRichard Henderson static bool trans_imm(DisasContext *dc, arg_imm *arg)
507e64b2e5cSRichard Henderson {
5082a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "imm")) {
5092a7567a2SRichard Henderson         return true;
5102a7567a2SRichard Henderson     }
511e64b2e5cSRichard Henderson     dc->ext_imm = arg->imm << 16;
512e64b2e5cSRichard Henderson     tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
5136f9642d7SRichard Henderson     dc->tb_flags_to_set = IMM_FLAG;
514e64b2e5cSRichard Henderson     return true;
515e64b2e5cSRichard Henderson }
516e64b2e5cSRichard Henderson 
51797955cebSRichard Henderson static void gen_mulh(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
51897955cebSRichard Henderson {
51997955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
52097955cebSRichard Henderson     tcg_gen_muls2_i32(tmp, out, ina, inb);
52197955cebSRichard Henderson     tcg_temp_free_i32(tmp);
52297955cebSRichard Henderson }
52397955cebSRichard Henderson 
52497955cebSRichard Henderson static void gen_mulhu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
52597955cebSRichard Henderson {
52697955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
52797955cebSRichard Henderson     tcg_gen_mulu2_i32(tmp, out, ina, inb);
52897955cebSRichard Henderson     tcg_temp_free_i32(tmp);
52997955cebSRichard Henderson }
53097955cebSRichard Henderson 
53197955cebSRichard Henderson static void gen_mulhsu(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
53297955cebSRichard Henderson {
53397955cebSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
53497955cebSRichard Henderson     tcg_gen_mulsu2_i32(tmp, out, ina, inb);
53597955cebSRichard Henderson     tcg_temp_free_i32(tmp);
53697955cebSRichard Henderson }
53797955cebSRichard Henderson 
53897955cebSRichard Henderson DO_TYPEA_CFG(mul, use_hw_mul, false, tcg_gen_mul_i32)
53997955cebSRichard Henderson DO_TYPEA_CFG(mulh, use_hw_mul >= 2, false, gen_mulh)
54097955cebSRichard Henderson DO_TYPEA_CFG(mulhu, use_hw_mul >= 2, false, gen_mulhu)
54197955cebSRichard Henderson DO_TYPEA_CFG(mulhsu, use_hw_mul >= 2, false, gen_mulhsu)
54297955cebSRichard Henderson DO_TYPEBI_CFG(muli, use_hw_mul, false, tcg_gen_muli_i32)
54397955cebSRichard Henderson 
544cb0a0a4cSRichard Henderson DO_TYPEA(or, false, tcg_gen_or_i32)
545cb0a0a4cSRichard Henderson DO_TYPEBI(ori, false, tcg_gen_ori_i32)
546cb0a0a4cSRichard Henderson 
547607f5767SRichard Henderson static void gen_pcmpeq(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
548607f5767SRichard Henderson {
549607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_EQ, out, ina, inb);
550607f5767SRichard Henderson }
551607f5767SRichard Henderson 
552607f5767SRichard Henderson static void gen_pcmpne(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
553607f5767SRichard Henderson {
554607f5767SRichard Henderson     tcg_gen_setcond_i32(TCG_COND_NE, out, ina, inb);
555607f5767SRichard Henderson }
556607f5767SRichard Henderson 
557607f5767SRichard Henderson DO_TYPEA_CFG(pcmpbf, use_pcmp_instr, false, gen_helper_pcmpbf)
558607f5767SRichard Henderson DO_TYPEA_CFG(pcmpeq, use_pcmp_instr, false, gen_pcmpeq)
559607f5767SRichard Henderson DO_TYPEA_CFG(pcmpne, use_pcmp_instr, false, gen_pcmpne)
560607f5767SRichard Henderson 
561a2b0b90eSRichard Henderson /* No input carry, but output carry. */
562a2b0b90eSRichard Henderson static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
563a2b0b90eSRichard Henderson {
564a2b0b90eSRichard Henderson     tcg_gen_setcond_i32(TCG_COND_GEU, cpu_msr_c, inb, ina);
565a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
566a2b0b90eSRichard Henderson }
567a2b0b90eSRichard Henderson 
568a2b0b90eSRichard Henderson /* Input and output carry. */
569a2b0b90eSRichard Henderson static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
570a2b0b90eSRichard Henderson {
571a2b0b90eSRichard Henderson     TCGv_i32 zero = tcg_const_i32(0);
572a2b0b90eSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
573a2b0b90eSRichard Henderson 
574a2b0b90eSRichard Henderson     tcg_gen_not_i32(tmp, ina);
575a2b0b90eSRichard Henderson     tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero);
576a2b0b90eSRichard Henderson     tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero);
577a2b0b90eSRichard Henderson 
578a2b0b90eSRichard Henderson     tcg_temp_free_i32(zero);
579a2b0b90eSRichard Henderson     tcg_temp_free_i32(tmp);
580a2b0b90eSRichard Henderson }
581a2b0b90eSRichard Henderson 
582a2b0b90eSRichard Henderson /* No input or output carry. */
583a2b0b90eSRichard Henderson static void gen_rsubk(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
584a2b0b90eSRichard Henderson {
585a2b0b90eSRichard Henderson     tcg_gen_sub_i32(out, inb, ina);
586a2b0b90eSRichard Henderson }
587a2b0b90eSRichard Henderson 
588a2b0b90eSRichard Henderson /* Input carry, no output carry. */
589a2b0b90eSRichard Henderson static void gen_rsubkc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb)
590a2b0b90eSRichard Henderson {
591a2b0b90eSRichard Henderson     TCGv_i32 nota = tcg_temp_new_i32();
592a2b0b90eSRichard Henderson 
593a2b0b90eSRichard Henderson     tcg_gen_not_i32(nota, ina);
594a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, inb, nota);
595a2b0b90eSRichard Henderson     tcg_gen_add_i32(out, out, cpu_msr_c);
596a2b0b90eSRichard Henderson 
597a2b0b90eSRichard Henderson     tcg_temp_free_i32(nota);
598a2b0b90eSRichard Henderson }
599a2b0b90eSRichard Henderson 
600a2b0b90eSRichard Henderson DO_TYPEA(rsub, true, gen_rsub)
601a2b0b90eSRichard Henderson DO_TYPEA(rsubc, true, gen_rsubc)
602a2b0b90eSRichard Henderson DO_TYPEA(rsubk, false, gen_rsubk)
603a2b0b90eSRichard Henderson DO_TYPEA(rsubkc, true, gen_rsubkc)
604a2b0b90eSRichard Henderson 
605a2b0b90eSRichard Henderson DO_TYPEBV(rsubi, true, gen_rsub)
606a2b0b90eSRichard Henderson DO_TYPEBV(rsubic, true, gen_rsubc)
607a2b0b90eSRichard Henderson DO_TYPEBV(rsubik, false, gen_rsubk)
608a2b0b90eSRichard Henderson DO_TYPEBV(rsubikc, true, gen_rsubkc)
609a2b0b90eSRichard Henderson 
61039cf3864SRichard Henderson DO_TYPEA0(sext8, false, tcg_gen_ext8s_i32)
61139cf3864SRichard Henderson DO_TYPEA0(sext16, false, tcg_gen_ext16s_i32)
61239cf3864SRichard Henderson 
61339cf3864SRichard Henderson static void gen_sra(TCGv_i32 out, TCGv_i32 ina)
61439cf3864SRichard Henderson {
61539cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
61639cf3864SRichard Henderson     tcg_gen_sari_i32(out, ina, 1);
61739cf3864SRichard Henderson }
61839cf3864SRichard Henderson 
61939cf3864SRichard Henderson static void gen_src(TCGv_i32 out, TCGv_i32 ina)
62039cf3864SRichard Henderson {
62139cf3864SRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
62239cf3864SRichard Henderson 
62339cf3864SRichard Henderson     tcg_gen_mov_i32(tmp, cpu_msr_c);
62439cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
62539cf3864SRichard Henderson     tcg_gen_extract2_i32(out, ina, tmp, 1);
62639cf3864SRichard Henderson 
62739cf3864SRichard Henderson     tcg_temp_free_i32(tmp);
62839cf3864SRichard Henderson }
62939cf3864SRichard Henderson 
63039cf3864SRichard Henderson static void gen_srl(TCGv_i32 out, TCGv_i32 ina)
63139cf3864SRichard Henderson {
63239cf3864SRichard Henderson     tcg_gen_andi_i32(cpu_msr_c, ina, 1);
63339cf3864SRichard Henderson     tcg_gen_shri_i32(out, ina, 1);
63439cf3864SRichard Henderson }
63539cf3864SRichard Henderson 
63639cf3864SRichard Henderson DO_TYPEA0(sra, false, gen_sra)
63739cf3864SRichard Henderson DO_TYPEA0(src, false, gen_src)
63839cf3864SRichard Henderson DO_TYPEA0(srl, false, gen_srl)
63939cf3864SRichard Henderson 
64039cf3864SRichard Henderson static void gen_swaph(TCGv_i32 out, TCGv_i32 ina)
64139cf3864SRichard Henderson {
64239cf3864SRichard Henderson     tcg_gen_rotri_i32(out, ina, 16);
64339cf3864SRichard Henderson }
64439cf3864SRichard Henderson 
64539cf3864SRichard Henderson DO_TYPEA0(swapb, false, tcg_gen_bswap32_i32)
64639cf3864SRichard Henderson DO_TYPEA0(swaph, false, gen_swaph)
64739cf3864SRichard Henderson 
64839cf3864SRichard Henderson static bool trans_wdic(DisasContext *dc, arg_wdic *a)
64939cf3864SRichard Henderson {
65039cf3864SRichard Henderson     /* Cache operations are nops: only check for supervisor mode.  */
65139cf3864SRichard Henderson     trap_userspace(dc, true);
65239cf3864SRichard Henderson     return true;
65339cf3864SRichard Henderson }
65439cf3864SRichard Henderson 
655cb0a0a4cSRichard Henderson DO_TYPEA(xor, false, tcg_gen_xor_i32)
656cb0a0a4cSRichard Henderson DO_TYPEBI(xori, false, tcg_gen_xori_i32)
657cb0a0a4cSRichard Henderson 
658d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
659d8e59c4aSRichard Henderson {
660d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
661d8e59c4aSRichard Henderson 
662d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
663d8e59c4aSRichard Henderson     if (ra && rb) {
664d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
665d8e59c4aSRichard Henderson         tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]);
666d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
667d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
668d8e59c4aSRichard Henderson     } else if (ra) {
669d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
670d8e59c4aSRichard Henderson     } else if (rb) {
671d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
672d8e59c4aSRichard Henderson     } else {
673d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, 0);
674d8e59c4aSRichard Henderson     }
675d8e59c4aSRichard Henderson 
6764b893631SRichard Henderson     if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
677d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
678d8e59c4aSRichard Henderson     }
679d8e59c4aSRichard Henderson     return ret;
680d8e59c4aSRichard Henderson }
681d8e59c4aSRichard Henderson 
682d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
683d8e59c4aSRichard Henderson {
684d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
685d8e59c4aSRichard Henderson 
686d8e59c4aSRichard Henderson     /* If any of the regs is r0, set t to the value of the other reg.  */
687d8e59c4aSRichard Henderson     if (ra) {
688d8e59c4aSRichard Henderson         TCGv_i32 tmp = tcg_temp_new_i32();
689d8e59c4aSRichard Henderson         tcg_gen_addi_i32(tmp, cpu_R[ra], imm);
690d8e59c4aSRichard Henderson         tcg_gen_extu_i32_tl(ret, tmp);
691d8e59c4aSRichard Henderson         tcg_temp_free_i32(tmp);
692d8e59c4aSRichard Henderson     } else {
693d8e59c4aSRichard Henderson         tcg_gen_movi_tl(ret, (uint32_t)imm);
694d8e59c4aSRichard Henderson     }
695d8e59c4aSRichard Henderson 
6964b893631SRichard Henderson     if (ra == 1 && dc->cfg->stackprot) {
697d8e59c4aSRichard Henderson         gen_helper_stackprot(cpu_env, ret);
698d8e59c4aSRichard Henderson     }
699d8e59c4aSRichard Henderson     return ret;
700d8e59c4aSRichard Henderson }
701d8e59c4aSRichard Henderson 
70219f27b6cSRichard Henderson #ifndef CONFIG_USER_ONLY
703d8e59c4aSRichard Henderson static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
704d8e59c4aSRichard Henderson {
7054b893631SRichard Henderson     int addr_size = dc->cfg->addr_size;
706d8e59c4aSRichard Henderson     TCGv ret = tcg_temp_new();
707d8e59c4aSRichard Henderson 
708d8e59c4aSRichard Henderson     if (addr_size == 32 || ra == 0) {
709d8e59c4aSRichard Henderson         if (rb) {
710d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[rb]);
711d8e59c4aSRichard Henderson         } else {
712d8e59c4aSRichard Henderson             tcg_gen_movi_tl(ret, 0);
713d8e59c4aSRichard Henderson         }
714d8e59c4aSRichard Henderson     } else {
715d8e59c4aSRichard Henderson         if (rb) {
716d8e59c4aSRichard Henderson             tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]);
717d8e59c4aSRichard Henderson         } else {
718d8e59c4aSRichard Henderson             tcg_gen_extu_i32_tl(ret, cpu_R[ra]);
719d8e59c4aSRichard Henderson             tcg_gen_shli_tl(ret, ret, 32);
720d8e59c4aSRichard Henderson         }
721d8e59c4aSRichard Henderson         if (addr_size < 64) {
722d8e59c4aSRichard Henderson             /* Mask off out of range bits.  */
723d8e59c4aSRichard Henderson             tcg_gen_andi_i64(ret, ret, MAKE_64BIT_MASK(0, addr_size));
724d8e59c4aSRichard Henderson         }
725d8e59c4aSRichard Henderson     }
726d8e59c4aSRichard Henderson     return ret;
727d8e59c4aSRichard Henderson }
72819f27b6cSRichard Henderson #endif
729d8e59c4aSRichard Henderson 
730ab0c8d0fSRichard Henderson static void record_unaligned_ess(DisasContext *dc, int rd,
731ab0c8d0fSRichard Henderson                                  MemOp size, bool store)
732ab0c8d0fSRichard Henderson {
733ab0c8d0fSRichard Henderson     uint32_t iflags = tcg_get_insn_start_param(dc->insn_start, 1);
734ab0c8d0fSRichard Henderson 
735ab0c8d0fSRichard Henderson     iflags |= ESR_ESS_FLAG;
736ab0c8d0fSRichard Henderson     iflags |= rd << 5;
737ab0c8d0fSRichard Henderson     iflags |= store * ESR_S;
738ab0c8d0fSRichard Henderson     iflags |= (size == MO_32) * ESR_W;
739ab0c8d0fSRichard Henderson 
740ab0c8d0fSRichard Henderson     tcg_set_insn_start_param(dc->insn_start, 1, iflags);
741ab0c8d0fSRichard Henderson }
742ab0c8d0fSRichard Henderson 
743d8e59c4aSRichard Henderson static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
744d8e59c4aSRichard Henderson                     int mem_index, bool rev)
745d8e59c4aSRichard Henderson {
746d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
747d8e59c4aSRichard Henderson 
748d8e59c4aSRichard Henderson     /*
749d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
750d8e59c4aSRichard Henderson      *
751d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
752d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
753d8e59c4aSRichard Henderson      */
754d8e59c4aSRichard Henderson     if (rev) {
755d8e59c4aSRichard Henderson         if (size > MO_8) {
756d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
757d8e59c4aSRichard Henderson         }
758d8e59c4aSRichard Henderson         if (size < MO_32) {
759d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
760d8e59c4aSRichard Henderson         }
761d8e59c4aSRichard Henderson     }
762d8e59c4aSRichard Henderson 
763ab0c8d0fSRichard Henderson     if (size > MO_8 &&
764ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
7654b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
766ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, false);
767ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
768d8e59c4aSRichard Henderson     }
769d8e59c4aSRichard Henderson 
770ab0c8d0fSRichard Henderson     tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
771d8e59c4aSRichard Henderson 
772d8e59c4aSRichard Henderson     tcg_temp_free(addr);
773d8e59c4aSRichard Henderson     return true;
774d8e59c4aSRichard Henderson }
775d8e59c4aSRichard Henderson 
776d8e59c4aSRichard Henderson static bool trans_lbu(DisasContext *dc, arg_typea *arg)
777d8e59c4aSRichard Henderson {
778d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
779d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
780d8e59c4aSRichard Henderson }
781d8e59c4aSRichard Henderson 
782d8e59c4aSRichard Henderson static bool trans_lbur(DisasContext *dc, arg_typea *arg)
783d8e59c4aSRichard Henderson {
784d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
785d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
786d8e59c4aSRichard Henderson }
787d8e59c4aSRichard Henderson 
788d8e59c4aSRichard Henderson static bool trans_lbuea(DisasContext *dc, arg_typea *arg)
789d8e59c4aSRichard Henderson {
790d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
791d8e59c4aSRichard Henderson         return true;
792d8e59c4aSRichard Henderson     }
79319f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
79419f27b6cSRichard Henderson     return true;
79519f27b6cSRichard Henderson #else
796d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
797d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
79819f27b6cSRichard Henderson #endif
799d8e59c4aSRichard Henderson }
800d8e59c4aSRichard Henderson 
801d8e59c4aSRichard Henderson static bool trans_lbui(DisasContext *dc, arg_typeb *arg)
802d8e59c4aSRichard Henderson {
803d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
804d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
805d8e59c4aSRichard Henderson }
806d8e59c4aSRichard Henderson 
807d8e59c4aSRichard Henderson static bool trans_lhu(DisasContext *dc, arg_typea *arg)
808d8e59c4aSRichard Henderson {
809d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
810d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
811d8e59c4aSRichard Henderson }
812d8e59c4aSRichard Henderson 
813d8e59c4aSRichard Henderson static bool trans_lhur(DisasContext *dc, arg_typea *arg)
814d8e59c4aSRichard Henderson {
815d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
816d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
817d8e59c4aSRichard Henderson }
818d8e59c4aSRichard Henderson 
819d8e59c4aSRichard Henderson static bool trans_lhuea(DisasContext *dc, arg_typea *arg)
820d8e59c4aSRichard Henderson {
821d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
822d8e59c4aSRichard Henderson         return true;
823d8e59c4aSRichard Henderson     }
82419f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
82519f27b6cSRichard Henderson     return true;
82619f27b6cSRichard Henderson #else
827d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
828d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
82919f27b6cSRichard Henderson #endif
830d8e59c4aSRichard Henderson }
831d8e59c4aSRichard Henderson 
832d8e59c4aSRichard Henderson static bool trans_lhui(DisasContext *dc, arg_typeb *arg)
833d8e59c4aSRichard Henderson {
834d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
835d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
836d8e59c4aSRichard Henderson }
837d8e59c4aSRichard Henderson 
838d8e59c4aSRichard Henderson static bool trans_lw(DisasContext *dc, arg_typea *arg)
839d8e59c4aSRichard Henderson {
840d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
841d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
842d8e59c4aSRichard Henderson }
843d8e59c4aSRichard Henderson 
844d8e59c4aSRichard Henderson static bool trans_lwr(DisasContext *dc, arg_typea *arg)
845d8e59c4aSRichard Henderson {
846d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
847d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
848d8e59c4aSRichard Henderson }
849d8e59c4aSRichard Henderson 
850d8e59c4aSRichard Henderson static bool trans_lwea(DisasContext *dc, arg_typea *arg)
851d8e59c4aSRichard Henderson {
852d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
853d8e59c4aSRichard Henderson         return true;
854d8e59c4aSRichard Henderson     }
85519f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
85619f27b6cSRichard Henderson     return true;
85719f27b6cSRichard Henderson #else
858d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
859d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
86019f27b6cSRichard Henderson #endif
861d8e59c4aSRichard Henderson }
862d8e59c4aSRichard Henderson 
863d8e59c4aSRichard Henderson static bool trans_lwi(DisasContext *dc, arg_typeb *arg)
864d8e59c4aSRichard Henderson {
865d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
866d8e59c4aSRichard Henderson     return do_load(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
867d8e59c4aSRichard Henderson }
868d8e59c4aSRichard Henderson 
869d8e59c4aSRichard Henderson static bool trans_lwx(DisasContext *dc, arg_typea *arg)
870d8e59c4aSRichard Henderson {
871d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
872d8e59c4aSRichard Henderson 
873d8e59c4aSRichard Henderson     /* lwx does not throw unaligned access errors, so force alignment */
874d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
875d8e59c4aSRichard Henderson 
876d8e59c4aSRichard Henderson     tcg_gen_qemu_ld_i32(cpu_res_val, addr, dc->mem_index, MO_TEUL);
877d8e59c4aSRichard Henderson     tcg_gen_mov_tl(cpu_res_addr, addr);
878d8e59c4aSRichard Henderson     tcg_temp_free(addr);
879d8e59c4aSRichard Henderson 
880d8e59c4aSRichard Henderson     if (arg->rd) {
881d8e59c4aSRichard Henderson         tcg_gen_mov_i32(cpu_R[arg->rd], cpu_res_val);
882d8e59c4aSRichard Henderson     }
883d8e59c4aSRichard Henderson 
884d8e59c4aSRichard Henderson     /* No support for AXI exclusive so always clear C */
885d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
886d8e59c4aSRichard Henderson     return true;
887d8e59c4aSRichard Henderson }
888d8e59c4aSRichard Henderson 
889d8e59c4aSRichard Henderson static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
890d8e59c4aSRichard Henderson                      int mem_index, bool rev)
891d8e59c4aSRichard Henderson {
892d8e59c4aSRichard Henderson     MemOp size = mop & MO_SIZE;
893d8e59c4aSRichard Henderson 
894d8e59c4aSRichard Henderson     /*
895d8e59c4aSRichard Henderson      * When doing reverse accesses we need to do two things.
896d8e59c4aSRichard Henderson      *
897d8e59c4aSRichard Henderson      * 1. Reverse the address wrt endianness.
898d8e59c4aSRichard Henderson      * 2. Byteswap the data lanes on the way back into the CPU core.
899d8e59c4aSRichard Henderson      */
900d8e59c4aSRichard Henderson     if (rev) {
901d8e59c4aSRichard Henderson         if (size > MO_8) {
902d8e59c4aSRichard Henderson             mop ^= MO_BSWAP;
903d8e59c4aSRichard Henderson         }
904d8e59c4aSRichard Henderson         if (size < MO_32) {
905d8e59c4aSRichard Henderson             tcg_gen_xori_tl(addr, addr, 3 - size);
906d8e59c4aSRichard Henderson         }
907d8e59c4aSRichard Henderson     }
908d8e59c4aSRichard Henderson 
909ab0c8d0fSRichard Henderson     if (size > MO_8 &&
910ab0c8d0fSRichard Henderson         (dc->tb_flags & MSR_EE) &&
9114b893631SRichard Henderson         dc->cfg->unaligned_exceptions) {
912ab0c8d0fSRichard Henderson         record_unaligned_ess(dc, rd, size, true);
913ab0c8d0fSRichard Henderson         mop |= MO_ALIGN;
914d8e59c4aSRichard Henderson     }
915d8e59c4aSRichard Henderson 
916ab0c8d0fSRichard Henderson     tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
917ab0c8d0fSRichard Henderson 
918d8e59c4aSRichard Henderson     tcg_temp_free(addr);
919d8e59c4aSRichard Henderson     return true;
920d8e59c4aSRichard Henderson }
921d8e59c4aSRichard Henderson 
922d8e59c4aSRichard Henderson static bool trans_sb(DisasContext *dc, arg_typea *arg)
923d8e59c4aSRichard Henderson {
924d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
925d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
926d8e59c4aSRichard Henderson }
927d8e59c4aSRichard Henderson 
928d8e59c4aSRichard Henderson static bool trans_sbr(DisasContext *dc, arg_typea *arg)
929d8e59c4aSRichard Henderson {
930d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
931d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, true);
932d8e59c4aSRichard Henderson }
933d8e59c4aSRichard Henderson 
934d8e59c4aSRichard Henderson static bool trans_sbea(DisasContext *dc, arg_typea *arg)
935d8e59c4aSRichard Henderson {
936d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
937d8e59c4aSRichard Henderson         return true;
938d8e59c4aSRichard Henderson     }
93919f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
94019f27b6cSRichard Henderson     return true;
94119f27b6cSRichard Henderson #else
942d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
943d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false);
94419f27b6cSRichard Henderson #endif
945d8e59c4aSRichard Henderson }
946d8e59c4aSRichard Henderson 
947d8e59c4aSRichard Henderson static bool trans_sbi(DisasContext *dc, arg_typeb *arg)
948d8e59c4aSRichard Henderson {
949d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
950d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_UB, dc->mem_index, false);
951d8e59c4aSRichard Henderson }
952d8e59c4aSRichard Henderson 
953d8e59c4aSRichard Henderson static bool trans_sh(DisasContext *dc, arg_typea *arg)
954d8e59c4aSRichard Henderson {
955d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
956d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
957d8e59c4aSRichard Henderson }
958d8e59c4aSRichard Henderson 
959d8e59c4aSRichard Henderson static bool trans_shr(DisasContext *dc, arg_typea *arg)
960d8e59c4aSRichard Henderson {
961d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
962d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, true);
963d8e59c4aSRichard Henderson }
964d8e59c4aSRichard Henderson 
965d8e59c4aSRichard Henderson static bool trans_shea(DisasContext *dc, arg_typea *arg)
966d8e59c4aSRichard Henderson {
967d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
968d8e59c4aSRichard Henderson         return true;
969d8e59c4aSRichard Henderson     }
97019f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
97119f27b6cSRichard Henderson     return true;
97219f27b6cSRichard Henderson #else
973d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
974d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, MMU_NOMMU_IDX, false);
97519f27b6cSRichard Henderson #endif
976d8e59c4aSRichard Henderson }
977d8e59c4aSRichard Henderson 
978d8e59c4aSRichard Henderson static bool trans_shi(DisasContext *dc, arg_typeb *arg)
979d8e59c4aSRichard Henderson {
980d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
981d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUW, dc->mem_index, false);
982d8e59c4aSRichard Henderson }
983d8e59c4aSRichard Henderson 
984d8e59c4aSRichard Henderson static bool trans_sw(DisasContext *dc, arg_typea *arg)
985d8e59c4aSRichard Henderson {
986d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
987d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
988d8e59c4aSRichard Henderson }
989d8e59c4aSRichard Henderson 
990d8e59c4aSRichard Henderson static bool trans_swr(DisasContext *dc, arg_typea *arg)
991d8e59c4aSRichard Henderson {
992d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
993d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, true);
994d8e59c4aSRichard Henderson }
995d8e59c4aSRichard Henderson 
996d8e59c4aSRichard Henderson static bool trans_swea(DisasContext *dc, arg_typea *arg)
997d8e59c4aSRichard Henderson {
998d8e59c4aSRichard Henderson     if (trap_userspace(dc, true)) {
999d8e59c4aSRichard Henderson         return true;
1000d8e59c4aSRichard Henderson     }
100119f27b6cSRichard Henderson #ifdef CONFIG_USER_ONLY
100219f27b6cSRichard Henderson     return true;
100319f27b6cSRichard Henderson #else
1004d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb);
1005d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, MMU_NOMMU_IDX, false);
100619f27b6cSRichard Henderson #endif
1007d8e59c4aSRichard Henderson }
1008d8e59c4aSRichard Henderson 
1009d8e59c4aSRichard Henderson static bool trans_swi(DisasContext *dc, arg_typeb *arg)
1010d8e59c4aSRichard Henderson {
1011d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typeb(dc, arg->ra, arg->imm);
1012d8e59c4aSRichard Henderson     return do_store(dc, arg->rd, addr, MO_TEUL, dc->mem_index, false);
1013d8e59c4aSRichard Henderson }
1014d8e59c4aSRichard Henderson 
1015d8e59c4aSRichard Henderson static bool trans_swx(DisasContext *dc, arg_typea *arg)
1016d8e59c4aSRichard Henderson {
1017d8e59c4aSRichard Henderson     TCGv addr = compute_ldst_addr_typea(dc, arg->ra, arg->rb);
1018d8e59c4aSRichard Henderson     TCGLabel *swx_done = gen_new_label();
1019d8e59c4aSRichard Henderson     TCGLabel *swx_fail = gen_new_label();
1020d8e59c4aSRichard Henderson     TCGv_i32 tval;
1021d8e59c4aSRichard Henderson 
1022d8e59c4aSRichard Henderson     /* swx does not throw unaligned access errors, so force alignment */
1023d8e59c4aSRichard Henderson     tcg_gen_andi_tl(addr, addr, ~3);
1024d8e59c4aSRichard Henderson 
1025d8e59c4aSRichard Henderson     /*
1026d8e59c4aSRichard Henderson      * Compare the address vs the one we used during lwx.
1027d8e59c4aSRichard Henderson      * On mismatch, the operation fails.  On match, addr dies at the
1028d8e59c4aSRichard Henderson      * branch, but we know we can use the equal version in the global.
1029d8e59c4aSRichard Henderson      * In either case, addr is no longer needed.
1030d8e59c4aSRichard Henderson      */
1031d8e59c4aSRichard Henderson     tcg_gen_brcond_tl(TCG_COND_NE, cpu_res_addr, addr, swx_fail);
1032d8e59c4aSRichard Henderson     tcg_temp_free(addr);
1033d8e59c4aSRichard Henderson 
1034d8e59c4aSRichard Henderson     /*
1035d8e59c4aSRichard Henderson      * Compare the value loaded during lwx with current contents of
1036d8e59c4aSRichard Henderson      * the reserved location.
1037d8e59c4aSRichard Henderson      */
1038d8e59c4aSRichard Henderson     tval = tcg_temp_new_i32();
1039d8e59c4aSRichard Henderson 
1040d8e59c4aSRichard Henderson     tcg_gen_atomic_cmpxchg_i32(tval, cpu_res_addr, cpu_res_val,
1041d8e59c4aSRichard Henderson                                reg_for_write(dc, arg->rd),
1042d8e59c4aSRichard Henderson                                dc->mem_index, MO_TEUL);
1043d8e59c4aSRichard Henderson 
1044d8e59c4aSRichard Henderson     tcg_gen_brcond_i32(TCG_COND_NE, cpu_res_val, tval, swx_fail);
1045d8e59c4aSRichard Henderson     tcg_temp_free_i32(tval);
1046d8e59c4aSRichard Henderson 
1047d8e59c4aSRichard Henderson     /* Success */
1048d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 0);
1049d8e59c4aSRichard Henderson     tcg_gen_br(swx_done);
1050d8e59c4aSRichard Henderson 
1051d8e59c4aSRichard Henderson     /* Failure */
1052d8e59c4aSRichard Henderson     gen_set_label(swx_fail);
1053d8e59c4aSRichard Henderson     tcg_gen_movi_i32(cpu_msr_c, 1);
1054d8e59c4aSRichard Henderson 
1055d8e59c4aSRichard Henderson     gen_set_label(swx_done);
1056d8e59c4aSRichard Henderson 
1057d8e59c4aSRichard Henderson     /*
1058d8e59c4aSRichard Henderson      * Prevent the saved address from working again without another ldx.
1059d8e59c4aSRichard Henderson      * Akin to the pseudocode setting reservation = 0.
1060d8e59c4aSRichard Henderson      */
1061d8e59c4aSRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1062d8e59c4aSRichard Henderson     return true;
1063d8e59c4aSRichard Henderson }
1064d8e59c4aSRichard Henderson 
106516bbbbc9SRichard Henderson static void setup_dslot(DisasContext *dc, bool type_b)
106616bbbbc9SRichard Henderson {
106716bbbbc9SRichard Henderson     dc->tb_flags_to_set |= D_FLAG;
106816bbbbc9SRichard Henderson     if (type_b && (dc->tb_flags & IMM_FLAG)) {
106916bbbbc9SRichard Henderson         dc->tb_flags_to_set |= BIMM_FLAG;
107016bbbbc9SRichard Henderson     }
107116bbbbc9SRichard Henderson }
107216bbbbc9SRichard Henderson 
107316bbbbc9SRichard Henderson static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
107416bbbbc9SRichard Henderson                       bool delay, bool abs, int link)
107516bbbbc9SRichard Henderson {
107616bbbbc9SRichard Henderson     uint32_t add_pc;
107716bbbbc9SRichard Henderson 
10782a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "branch")) {
10792a7567a2SRichard Henderson         return true;
10802a7567a2SRichard Henderson     }
108116bbbbc9SRichard Henderson     if (delay) {
108216bbbbc9SRichard Henderson         setup_dslot(dc, dest_rb < 0);
108316bbbbc9SRichard Henderson     }
108416bbbbc9SRichard Henderson 
108516bbbbc9SRichard Henderson     if (link) {
108616bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_R[link], dc->base.pc_next);
108716bbbbc9SRichard Henderson     }
108816bbbbc9SRichard Henderson 
108916bbbbc9SRichard Henderson     /* Store the branch taken destination into btarget.  */
109016bbbbc9SRichard Henderson     add_pc = abs ? 0 : dc->base.pc_next;
109116bbbbc9SRichard Henderson     if (dest_rb > 0) {
109216bbbbc9SRichard Henderson         dc->jmp_dest = -1;
109316bbbbc9SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], add_pc);
109416bbbbc9SRichard Henderson     } else {
109516bbbbc9SRichard Henderson         dc->jmp_dest = add_pc + dest_imm;
109616bbbbc9SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
109716bbbbc9SRichard Henderson     }
109816bbbbc9SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
109916bbbbc9SRichard Henderson     return true;
110016bbbbc9SRichard Henderson }
110116bbbbc9SRichard Henderson 
110216bbbbc9SRichard Henderson #define DO_BR(NAME, NAMEI, DELAY, ABS, LINK)                               \
110316bbbbc9SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_br *arg)          \
110416bbbbc9SRichard Henderson     { return do_branch(dc, arg->rb, 0, DELAY, ABS, LINK ? arg->rd : 0); }  \
110516bbbbc9SRichard Henderson     static bool trans_##NAMEI(DisasContext *dc, arg_typeb_br *arg)         \
110616bbbbc9SRichard Henderson     { return do_branch(dc, -1, arg->imm, DELAY, ABS, LINK ? arg->rd : 0); }
110716bbbbc9SRichard Henderson 
110816bbbbc9SRichard Henderson DO_BR(br, bri, false, false, false)
110916bbbbc9SRichard Henderson DO_BR(bra, brai, false, true, false)
111016bbbbc9SRichard Henderson DO_BR(brd, brid, true, false, false)
111116bbbbc9SRichard Henderson DO_BR(brad, braid, true, true, false)
111216bbbbc9SRichard Henderson DO_BR(brld, brlid, true, false, true)
111316bbbbc9SRichard Henderson DO_BR(brald, bralid, true, true, true)
111416bbbbc9SRichard Henderson 
1115fd779113SRichard Henderson static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
1116fd779113SRichard Henderson                    TCGCond cond, int ra, bool delay)
1117fd779113SRichard Henderson {
1118fd779113SRichard Henderson     TCGv_i32 zero, next;
1119fd779113SRichard Henderson 
11202a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "bcc")) {
11212a7567a2SRichard Henderson         return true;
11222a7567a2SRichard Henderson     }
1123fd779113SRichard Henderson     if (delay) {
1124fd779113SRichard Henderson         setup_dslot(dc, dest_rb < 0);
1125fd779113SRichard Henderson     }
1126fd779113SRichard Henderson 
1127fd779113SRichard Henderson     dc->jmp_cond = cond;
1128fd779113SRichard Henderson 
1129fd779113SRichard Henderson     /* Cache the condition register in cpu_bvalue across any delay slot.  */
1130fd779113SRichard Henderson     tcg_gen_mov_i32(cpu_bvalue, reg_for_read(dc, ra));
1131fd779113SRichard Henderson 
1132fd779113SRichard Henderson     /* Store the branch taken destination into btarget.  */
1133fd779113SRichard Henderson     if (dest_rb > 0) {
1134fd779113SRichard Henderson         dc->jmp_dest = -1;
1135fd779113SRichard Henderson         tcg_gen_addi_i32(cpu_btarget, cpu_R[dest_rb], dc->base.pc_next);
1136fd779113SRichard Henderson     } else {
1137fd779113SRichard Henderson         dc->jmp_dest = dc->base.pc_next + dest_imm;
1138fd779113SRichard Henderson         tcg_gen_movi_i32(cpu_btarget, dc->jmp_dest);
1139fd779113SRichard Henderson     }
1140fd779113SRichard Henderson 
1141fd779113SRichard Henderson     /* Compute the final destination into btarget.  */
1142fd779113SRichard Henderson     zero = tcg_const_i32(0);
1143fd779113SRichard Henderson     next = tcg_const_i32(dc->base.pc_next + (delay + 1) * 4);
1144fd779113SRichard Henderson     tcg_gen_movcond_i32(dc->jmp_cond, cpu_btarget,
1145fd779113SRichard Henderson                         reg_for_read(dc, ra), zero,
1146fd779113SRichard Henderson                         cpu_btarget, next);
1147fd779113SRichard Henderson     tcg_temp_free_i32(zero);
1148fd779113SRichard Henderson     tcg_temp_free_i32(next);
1149fd779113SRichard Henderson 
1150fd779113SRichard Henderson     return true;
1151fd779113SRichard Henderson }
1152fd779113SRichard Henderson 
1153fd779113SRichard Henderson #define DO_BCC(NAME, COND)                                              \
1154fd779113SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typea_bc *arg)       \
1155fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, false); }            \
1156fd779113SRichard Henderson     static bool trans_##NAME##d(DisasContext *dc, arg_typea_bc *arg)    \
1157fd779113SRichard Henderson     { return do_bcc(dc, arg->rb, 0, COND, arg->ra, true); }             \
1158fd779113SRichard Henderson     static bool trans_##NAME##i(DisasContext *dc, arg_typeb_bc *arg)    \
1159fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, false); }          \
1160fd779113SRichard Henderson     static bool trans_##NAME##id(DisasContext *dc, arg_typeb_bc *arg)   \
1161fd779113SRichard Henderson     { return do_bcc(dc, -1, arg->imm, COND, arg->ra, true); }
1162fd779113SRichard Henderson 
1163fd779113SRichard Henderson DO_BCC(beq, TCG_COND_EQ)
1164fd779113SRichard Henderson DO_BCC(bge, TCG_COND_GE)
1165fd779113SRichard Henderson DO_BCC(bgt, TCG_COND_GT)
1166fd779113SRichard Henderson DO_BCC(ble, TCG_COND_LE)
1167fd779113SRichard Henderson DO_BCC(blt, TCG_COND_LT)
1168fd779113SRichard Henderson DO_BCC(bne, TCG_COND_NE)
1169fd779113SRichard Henderson 
1170f5235314SRichard Henderson static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
1171f5235314SRichard Henderson {
1172f5235314SRichard Henderson     if (trap_userspace(dc, true)) {
1173f5235314SRichard Henderson         return true;
1174f5235314SRichard Henderson     }
11752a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brk")) {
11762a7567a2SRichard Henderson         return true;
11772a7567a2SRichard Henderson     }
11782a7567a2SRichard Henderson 
1179f5235314SRichard Henderson     tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
1180f5235314SRichard Henderson     if (arg->rd) {
1181f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1182f5235314SRichard Henderson     }
1183f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
1184f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1185f5235314SRichard Henderson 
118617e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1187f5235314SRichard Henderson     return true;
1188f5235314SRichard Henderson }
1189f5235314SRichard Henderson 
1190f5235314SRichard Henderson static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
1191f5235314SRichard Henderson {
1192f5235314SRichard Henderson     uint32_t imm = arg->imm;
1193f5235314SRichard Henderson 
1194f5235314SRichard Henderson     if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
1195f5235314SRichard Henderson         return true;
1196f5235314SRichard Henderson     }
11972a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "brki")) {
11982a7567a2SRichard Henderson         return true;
11992a7567a2SRichard Henderson     }
12002a7567a2SRichard Henderson 
1201f5235314SRichard Henderson     tcg_gen_movi_i32(cpu_pc, imm);
1202f5235314SRichard Henderson     if (arg->rd) {
1203f5235314SRichard Henderson         tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
1204f5235314SRichard Henderson     }
1205f5235314SRichard Henderson     tcg_gen_movi_tl(cpu_res_addr, -1);
1206f5235314SRichard Henderson 
1207f5235314SRichard Henderson #ifdef CONFIG_USER_ONLY
1208f5235314SRichard Henderson     switch (imm) {
1209f5235314SRichard Henderson     case 0x8:  /* syscall trap */
1210f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_SYSCALL);
1211f5235314SRichard Henderson         break;
1212f5235314SRichard Henderson     case 0x18: /* debug trap */
1213f5235314SRichard Henderson         gen_raise_exception_sync(dc, EXCP_DEBUG);
1214f5235314SRichard Henderson         break;
1215f5235314SRichard Henderson     default:   /* eliminated with trap_userspace check */
1216f5235314SRichard Henderson         g_assert_not_reached();
1217f5235314SRichard Henderson     }
1218f5235314SRichard Henderson #else
1219f5235314SRichard Henderson     uint32_t msr_to_set = 0;
1220f5235314SRichard Henderson 
1221f5235314SRichard Henderson     if (imm != 0x18) {
1222f5235314SRichard Henderson         msr_to_set |= MSR_BIP;
1223f5235314SRichard Henderson     }
1224f5235314SRichard Henderson     if (imm == 0x8 || imm == 0x18) {
1225f5235314SRichard Henderson         /* MSR_UM and MSR_VM are in tb_flags, so we know their value. */
1226f5235314SRichard Henderson         msr_to_set |= (dc->tb_flags & (MSR_UM | MSR_VM)) << 1;
1227f5235314SRichard Henderson         tcg_gen_andi_i32(cpu_msr, cpu_msr,
1228f5235314SRichard Henderson                          ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
1229f5235314SRichard Henderson     }
1230f5235314SRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
123117e77796SRichard Henderson     dc->base.is_jmp = DISAS_EXIT;
1232f5235314SRichard Henderson #endif
1233f5235314SRichard Henderson 
1234f5235314SRichard Henderson     return true;
1235f5235314SRichard Henderson }
1236f5235314SRichard Henderson 
1237ee8c7f9fSRichard Henderson static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
1238ee8c7f9fSRichard Henderson {
1239ee8c7f9fSRichard Henderson     int mbar_imm = arg->imm;
1240ee8c7f9fSRichard Henderson 
12412a7567a2SRichard Henderson     /* Note that mbar is a specialized branch instruction. */
12422a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "mbar")) {
12432a7567a2SRichard Henderson         return true;
12442a7567a2SRichard Henderson     }
12452a7567a2SRichard Henderson 
1246ee8c7f9fSRichard Henderson     /* Data access memory barrier.  */
1247ee8c7f9fSRichard Henderson     if ((mbar_imm & 2) == 0) {
1248ee8c7f9fSRichard Henderson         tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
1249ee8c7f9fSRichard Henderson     }
1250ee8c7f9fSRichard Henderson 
1251ee8c7f9fSRichard Henderson     /* Sleep. */
1252ee8c7f9fSRichard Henderson     if (mbar_imm & 16) {
1253ee8c7f9fSRichard Henderson         TCGv_i32 tmp_1;
1254ee8c7f9fSRichard Henderson 
1255ee8c7f9fSRichard Henderson         if (trap_userspace(dc, true)) {
1256ee8c7f9fSRichard Henderson             /* Sleep is a privileged instruction.  */
1257ee8c7f9fSRichard Henderson             return true;
1258ee8c7f9fSRichard Henderson         }
1259ee8c7f9fSRichard Henderson 
1260ee8c7f9fSRichard Henderson         t_sync_flags(dc);
1261ee8c7f9fSRichard Henderson 
1262ee8c7f9fSRichard Henderson         tmp_1 = tcg_const_i32(1);
1263ee8c7f9fSRichard Henderson         tcg_gen_st_i32(tmp_1, cpu_env,
1264ee8c7f9fSRichard Henderson                        -offsetof(MicroBlazeCPU, env)
1265ee8c7f9fSRichard Henderson                        +offsetof(CPUState, halted));
1266ee8c7f9fSRichard Henderson         tcg_temp_free_i32(tmp_1);
1267ee8c7f9fSRichard Henderson 
1268ee8c7f9fSRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next + 4);
1269ee8c7f9fSRichard Henderson 
1270ee8c7f9fSRichard Henderson         gen_raise_exception(dc, EXCP_HLT);
1271ee8c7f9fSRichard Henderson     }
1272ee8c7f9fSRichard Henderson 
1273ee8c7f9fSRichard Henderson     /*
1274ee8c7f9fSRichard Henderson      * If !(mbar_imm & 1), this is an instruction access memory barrier
1275ee8c7f9fSRichard Henderson      * and we need to end the TB so that we recognize self-modified
1276ee8c7f9fSRichard Henderson      * code immediately.
1277ee8c7f9fSRichard Henderson      *
1278ee8c7f9fSRichard Henderson      * However, there are some data mbars that need the TB break
1279ee8c7f9fSRichard Henderson      * (and return to main loop) to recognize interrupts right away.
1280ee8c7f9fSRichard Henderson      * E.g. recognizing a change to an interrupt controller register.
1281ee8c7f9fSRichard Henderson      *
1282ee8c7f9fSRichard Henderson      * Therefore, choose to end the TB always.
1283ee8c7f9fSRichard Henderson      */
128443b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
1285ee8c7f9fSRichard Henderson     return true;
1286ee8c7f9fSRichard Henderson }
1287ee8c7f9fSRichard Henderson 
1288e6cb0354SRichard Henderson static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
1289e6cb0354SRichard Henderson {
1290e6cb0354SRichard Henderson     if (trap_userspace(dc, to_set)) {
1291e6cb0354SRichard Henderson         return true;
1292e6cb0354SRichard Henderson     }
12932a7567a2SRichard Henderson     if (invalid_delay_slot(dc, "rts")) {
12942a7567a2SRichard Henderson         return true;
12952a7567a2SRichard Henderson     }
12962a7567a2SRichard Henderson 
1297e6cb0354SRichard Henderson     dc->tb_flags_to_set |= to_set;
1298e6cb0354SRichard Henderson     setup_dslot(dc, true);
1299e6cb0354SRichard Henderson 
1300e6cb0354SRichard Henderson     dc->jmp_cond = TCG_COND_ALWAYS;
1301e6cb0354SRichard Henderson     dc->jmp_dest = -1;
1302e6cb0354SRichard Henderson     tcg_gen_addi_i32(cpu_btarget, reg_for_read(dc, arg->ra), arg->imm);
1303e6cb0354SRichard Henderson     return true;
1304e6cb0354SRichard Henderson }
1305e6cb0354SRichard Henderson 
1306e6cb0354SRichard Henderson #define DO_RTS(NAME, IFLAG) \
1307e6cb0354SRichard Henderson     static bool trans_##NAME(DisasContext *dc, arg_typeb_bc *arg) \
1308e6cb0354SRichard Henderson     { return do_rts(dc, arg, IFLAG); }
1309e6cb0354SRichard Henderson 
1310e6cb0354SRichard Henderson DO_RTS(rtbd, DRTB_FLAG)
1311e6cb0354SRichard Henderson DO_RTS(rtid, DRTI_FLAG)
1312e6cb0354SRichard Henderson DO_RTS(rted, DRTE_FLAG)
1313e6cb0354SRichard Henderson DO_RTS(rtsd, 0)
1314e6cb0354SRichard Henderson 
131520800179SRichard Henderson static bool trans_zero(DisasContext *dc, arg_zero *arg)
131620800179SRichard Henderson {
131720800179SRichard Henderson     /* If opcode_0_illegal, trap.  */
13184b893631SRichard Henderson     if (dc->cfg->opcode_0_illegal) {
131920800179SRichard Henderson         trap_illegal(dc, true);
132020800179SRichard Henderson         return true;
132120800179SRichard Henderson     }
132220800179SRichard Henderson     /*
132320800179SRichard Henderson      * Otherwise, this is "add r0, r0, r0".
132420800179SRichard Henderson      * Continue to trans_add so that MSR[C] gets cleared.
132520800179SRichard Henderson      */
132620800179SRichard Henderson     return false;
1327fcf5ef2aSThomas Huth }
1328fcf5ef2aSThomas Huth 
13291074c0fbSRichard Henderson static void msr_read(DisasContext *dc, TCGv_i32 d)
1330fcf5ef2aSThomas Huth {
13311074c0fbSRichard Henderson     TCGv_i32 t;
13321074c0fbSRichard Henderson 
13331074c0fbSRichard Henderson     /* Replicate the cpu_msr_c boolean into the proper bit and the copy. */
13341074c0fbSRichard Henderson     t = tcg_temp_new_i32();
13351074c0fbSRichard Henderson     tcg_gen_muli_i32(t, cpu_msr_c, MSR_C | MSR_CC);
13361074c0fbSRichard Henderson     tcg_gen_or_i32(d, cpu_msr, t);
13371074c0fbSRichard Henderson     tcg_temp_free_i32(t);
1338fcf5ef2aSThomas Huth }
1339fcf5ef2aSThomas Huth 
1340536e340fSRichard Henderson static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
1341536e340fSRichard Henderson {
1342536e340fSRichard Henderson     uint32_t imm = arg->imm;
1343536e340fSRichard Henderson 
1344536e340fSRichard Henderson     if (trap_userspace(dc, imm != MSR_C)) {
1345536e340fSRichard Henderson         return true;
1346536e340fSRichard Henderson     }
1347536e340fSRichard Henderson 
1348536e340fSRichard Henderson     if (arg->rd) {
1349536e340fSRichard Henderson         msr_read(dc, cpu_R[arg->rd]);
1350536e340fSRichard Henderson     }
1351536e340fSRichard Henderson 
1352536e340fSRichard Henderson     /*
1353536e340fSRichard Henderson      * Handle the carry bit separately.
1354536e340fSRichard Henderson      * This is the only bit that userspace can modify.
1355536e340fSRichard Henderson      */
1356536e340fSRichard Henderson     if (imm & MSR_C) {
1357536e340fSRichard Henderson         tcg_gen_movi_i32(cpu_msr_c, set);
1358536e340fSRichard Henderson     }
1359536e340fSRichard Henderson 
1360536e340fSRichard Henderson     /*
1361536e340fSRichard Henderson      * MSR_C and MSR_CC set above.
1362536e340fSRichard Henderson      * MSR_PVR is not writable, and is always clear.
1363536e340fSRichard Henderson      */
1364536e340fSRichard Henderson     imm &= ~(MSR_C | MSR_CC | MSR_PVR);
1365536e340fSRichard Henderson 
1366536e340fSRichard Henderson     if (imm != 0) {
1367536e340fSRichard Henderson         if (set) {
1368536e340fSRichard Henderson             tcg_gen_ori_i32(cpu_msr, cpu_msr, imm);
1369536e340fSRichard Henderson         } else {
1370536e340fSRichard Henderson             tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
1371536e340fSRichard Henderson         }
137243b34134SRichard Henderson         dc->base.is_jmp = DISAS_EXIT_NEXT;
1373536e340fSRichard Henderson     }
1374536e340fSRichard Henderson     return true;
1375536e340fSRichard Henderson }
1376536e340fSRichard Henderson 
1377536e340fSRichard Henderson static bool trans_msrclr(DisasContext *dc, arg_type_msr *arg)
1378536e340fSRichard Henderson {
1379536e340fSRichard Henderson     return do_msrclrset(dc, arg, false);
1380536e340fSRichard Henderson }
1381536e340fSRichard Henderson 
1382536e340fSRichard Henderson static bool trans_msrset(DisasContext *dc, arg_type_msr *arg)
1383536e340fSRichard Henderson {
1384536e340fSRichard Henderson     return do_msrclrset(dc, arg, true);
1385536e340fSRichard Henderson }
1386536e340fSRichard Henderson 
13879df297a2SRichard Henderson static bool trans_mts(DisasContext *dc, arg_mts *arg)
1388fcf5ef2aSThomas Huth {
13899df297a2SRichard Henderson     if (trap_userspace(dc, true)) {
13909df297a2SRichard Henderson         return true;
1391f0f7e7f7SEdgar E. Iglesias     }
1392f0f7e7f7SEdgar E. Iglesias 
13939df297a2SRichard Henderson #ifdef CONFIG_USER_ONLY
13949df297a2SRichard Henderson     g_assert_not_reached();
13959df297a2SRichard Henderson #else
13969df297a2SRichard Henderson     if (arg->e && arg->rs != 0x1003) {
13979df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR,
13989df297a2SRichard Henderson                       "Invalid extended mts reg 0x%x\n", arg->rs);
13999df297a2SRichard Henderson         return true;
14002023e9a3SEdgar E. Iglesias     }
1401fcf5ef2aSThomas Huth 
14029df297a2SRichard Henderson     TCGv_i32 src = reg_for_read(dc, arg->ra);
14039df297a2SRichard Henderson     switch (arg->rs) {
1404aa28e6d4SRichard Henderson     case SR_MSR:
140543b34134SRichard Henderson         /* Install MSR_C.  */
140643b34134SRichard Henderson         tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
140743b34134SRichard Henderson         /*
140843b34134SRichard Henderson          * Clear MSR_C and MSR_CC;
140943b34134SRichard Henderson          * MSR_PVR is not writable, and is always clear.
141043b34134SRichard Henderson          */
141143b34134SRichard Henderson         tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
1412fcf5ef2aSThomas Huth         break;
14139df297a2SRichard Henderson     case SR_FSR:
14149df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr));
14159df297a2SRichard Henderson         break;
14169df297a2SRichard Henderson     case 0x800:
14179df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, slr));
14189df297a2SRichard Henderson         break;
14199df297a2SRichard Henderson     case 0x802:
14209df297a2SRichard Henderson         tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, shr));
14219df297a2SRichard Henderson         break;
14229df297a2SRichard Henderson 
14239df297a2SRichard Henderson     case 0x1000: /* PID */
14249df297a2SRichard Henderson     case 0x1001: /* ZPR */
14259df297a2SRichard Henderson     case 0x1002: /* TLBX */
14269df297a2SRichard Henderson     case 0x1003: /* TLBLO */
14279df297a2SRichard Henderson     case 0x1004: /* TLBHI */
14289df297a2SRichard Henderson     case 0x1005: /* TLBSX */
14299df297a2SRichard Henderson         {
14309df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
14319df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
14329df297a2SRichard Henderson 
14339df297a2SRichard Henderson             gen_helper_mmu_write(cpu_env, tmp_ext, tmp_reg, src);
14349df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
14359df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
14369df297a2SRichard Henderson         }
14379df297a2SRichard Henderson         break;
14389df297a2SRichard Henderson 
14399df297a2SRichard Henderson     default:
14409df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
14419df297a2SRichard Henderson         return true;
14429df297a2SRichard Henderson     }
144343b34134SRichard Henderson     dc->base.is_jmp = DISAS_EXIT_NEXT;
14449df297a2SRichard Henderson     return true;
14459df297a2SRichard Henderson #endif
14469df297a2SRichard Henderson }
14479df297a2SRichard Henderson 
14489df297a2SRichard Henderson static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
14499df297a2SRichard Henderson {
14509df297a2SRichard Henderson     TCGv_i32 dest = reg_for_write(dc, arg->rd);
14519df297a2SRichard Henderson 
14529df297a2SRichard Henderson     if (arg->e) {
14539df297a2SRichard Henderson         switch (arg->rs) {
1454351527b7SEdgar E. Iglesias         case SR_EAR:
1455dbdb77c4SRichard Henderson             {
1456dbdb77c4SRichard Henderson                 TCGv_i64 t64 = tcg_temp_new_i64();
14579df297a2SRichard Henderson                 tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
14589df297a2SRichard Henderson                 tcg_gen_extrh_i64_i32(dest, t64);
1459dbdb77c4SRichard Henderson                 tcg_temp_free_i64(t64);
1460dbdb77c4SRichard Henderson             }
14619df297a2SRichard Henderson             return true;
14629df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
14639df297a2SRichard Henderson         case 0x1003: /* TLBLO */
14649df297a2SRichard Henderson             /* Handled below. */
1465aa28e6d4SRichard Henderson             break;
14669df297a2SRichard Henderson #endif
14679df297a2SRichard Henderson         case 0x2006 ... 0x2009:
14689df297a2SRichard Henderson             /* High bits of PVR6-9 not implemented. */
14699df297a2SRichard Henderson             tcg_gen_movi_i32(dest, 0);
14709df297a2SRichard Henderson             return true;
1471fcf5ef2aSThomas Huth         default:
14729df297a2SRichard Henderson             qemu_log_mask(LOG_GUEST_ERROR,
14739df297a2SRichard Henderson                           "Invalid extended mfs reg 0x%x\n", arg->rs);
14749df297a2SRichard Henderson             return true;
1475fcf5ef2aSThomas Huth         }
14769df297a2SRichard Henderson     }
14779df297a2SRichard Henderson 
14789df297a2SRichard Henderson     switch (arg->rs) {
1479aa28e6d4SRichard Henderson     case SR_PC:
14809df297a2SRichard Henderson         tcg_gen_movi_i32(dest, dc->base.pc_next);
1481fcf5ef2aSThomas Huth         break;
1482aa28e6d4SRichard Henderson     case SR_MSR:
14839df297a2SRichard Henderson         msr_read(dc, dest);
1484fcf5ef2aSThomas Huth         break;
1485351527b7SEdgar E. Iglesias     case SR_EAR:
1486dbdb77c4SRichard Henderson         {
1487dbdb77c4SRichard Henderson             TCGv_i64 t64 = tcg_temp_new_i64();
1488dbdb77c4SRichard Henderson             tcg_gen_ld_i64(t64, cpu_env, offsetof(CPUMBState, ear));
14899df297a2SRichard Henderson             tcg_gen_extrl_i64_i32(dest, t64);
1490dbdb77c4SRichard Henderson             tcg_temp_free_i64(t64);
1491a1b48e3aSEdgar E. Iglesias         }
1492aa28e6d4SRichard Henderson         break;
1493351527b7SEdgar E. Iglesias     case SR_ESR:
14949df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, esr));
1495aa28e6d4SRichard Henderson         break;
1496351527b7SEdgar E. Iglesias     case SR_FSR:
14979df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, fsr));
1498aa28e6d4SRichard Henderson         break;
1499351527b7SEdgar E. Iglesias     case SR_BTR:
15009df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, btr));
1501aa28e6d4SRichard Henderson         break;
15027cdae31dSTong Ho     case SR_EDR:
15039df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, edr));
1504fcf5ef2aSThomas Huth         break;
1505fcf5ef2aSThomas Huth     case 0x800:
15069df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, slr));
1507fcf5ef2aSThomas Huth         break;
1508fcf5ef2aSThomas Huth     case 0x802:
15099df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env, offsetof(CPUMBState, shr));
1510fcf5ef2aSThomas Huth         break;
15119df297a2SRichard Henderson 
15129df297a2SRichard Henderson #ifndef CONFIG_USER_ONLY
15139df297a2SRichard Henderson     case 0x1000: /* PID */
15149df297a2SRichard Henderson     case 0x1001: /* ZPR */
15159df297a2SRichard Henderson     case 0x1002: /* TLBX */
15169df297a2SRichard Henderson     case 0x1003: /* TLBLO */
15179df297a2SRichard Henderson     case 0x1004: /* TLBHI */
15189df297a2SRichard Henderson     case 0x1005: /* TLBSX */
15199df297a2SRichard Henderson         {
15209df297a2SRichard Henderson             TCGv_i32 tmp_ext = tcg_const_i32(arg->e);
15219df297a2SRichard Henderson             TCGv_i32 tmp_reg = tcg_const_i32(arg->rs & 7);
15229df297a2SRichard Henderson 
15239df297a2SRichard Henderson             gen_helper_mmu_read(dest, cpu_env, tmp_ext, tmp_reg);
15249df297a2SRichard Henderson             tcg_temp_free_i32(tmp_reg);
15259df297a2SRichard Henderson             tcg_temp_free_i32(tmp_ext);
15269df297a2SRichard Henderson         }
15279df297a2SRichard Henderson         break;
15289df297a2SRichard Henderson #endif
15299df297a2SRichard Henderson 
1530351527b7SEdgar E. Iglesias     case 0x2000 ... 0x200c:
15319df297a2SRichard Henderson         tcg_gen_ld_i32(dest, cpu_env,
1532a4bcfc33SRichard Henderson                        offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
1533a4bcfc33SRichard Henderson                        - offsetof(MicroBlazeCPU, env));
1534fcf5ef2aSThomas Huth         break;
1535fcf5ef2aSThomas Huth     default:
15369df297a2SRichard Henderson         qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
1537fcf5ef2aSThomas Huth         break;
1538fcf5ef2aSThomas Huth     }
15399df297a2SRichard Henderson     return true;
1540fcf5ef2aSThomas Huth }
1541fcf5ef2aSThomas Huth 
15423fb394fdSRichard Henderson static void do_rti(DisasContext *dc)
1543fcf5ef2aSThomas Huth {
15443fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1545fcf5ef2aSThomas Huth 
15463fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15473fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_IE);
15483fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, MSR_VM | MSR_UM);
15493fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM));
15503fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15513fb394fdSRichard Henderson 
15523fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1553fcf5ef2aSThomas Huth }
1554fcf5ef2aSThomas Huth 
15553fb394fdSRichard Henderson static void do_rtb(DisasContext *dc)
1556fcf5ef2aSThomas Huth {
15573fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1558fcf5ef2aSThomas Huth 
15593fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15603fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_BIP));
15613fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15623fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
15633fb394fdSRichard Henderson 
15643fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1565fcf5ef2aSThomas Huth }
1566fcf5ef2aSThomas Huth 
15673fb394fdSRichard Henderson static void do_rte(DisasContext *dc)
1568fcf5ef2aSThomas Huth {
15693fb394fdSRichard Henderson     TCGv_i32 tmp = tcg_temp_new_i32();
1570fcf5ef2aSThomas Huth 
15713fb394fdSRichard Henderson     tcg_gen_shri_i32(tmp, cpu_msr, 1);
15723fb394fdSRichard Henderson     tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_EE);
15733fb394fdSRichard Henderson     tcg_gen_andi_i32(tmp, tmp, (MSR_VM | MSR_UM));
15743fb394fdSRichard Henderson     tcg_gen_andi_i32(cpu_msr, cpu_msr, ~(MSR_VM | MSR_UM | MSR_EIP));
15753fb394fdSRichard Henderson     tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
1576fcf5ef2aSThomas Huth 
15773fb394fdSRichard Henderson     tcg_temp_free_i32(tmp);
1578fcf5ef2aSThomas Huth }
1579fcf5ef2aSThomas Huth 
1580fcf5ef2aSThomas Huth /* Insns connected to FSL or AXI stream attached devices.  */
158152065d8fSRichard Henderson static bool do_get(DisasContext *dc, int rd, int rb, int imm, int ctrl)
1582fcf5ef2aSThomas Huth {
1583fcf5ef2aSThomas Huth     TCGv_i32 t_id, t_ctrl;
1584fcf5ef2aSThomas Huth 
1585bdfc1e88SEdgar E. Iglesias     if (trap_userspace(dc, true)) {
158652065d8fSRichard Henderson         return true;
1587fcf5ef2aSThomas Huth     }
1588fcf5ef2aSThomas Huth 
1589cfeea807SEdgar E. Iglesias     t_id = tcg_temp_new_i32();
159052065d8fSRichard Henderson     if (rb) {
159152065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
1592fcf5ef2aSThomas Huth     } else {
159352065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
1594fcf5ef2aSThomas Huth     }
1595fcf5ef2aSThomas Huth 
1596cfeea807SEdgar E. Iglesias     t_ctrl = tcg_const_i32(ctrl);
159752065d8fSRichard Henderson     gen_helper_get(reg_for_write(dc, rd), t_id, t_ctrl);
1598cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_id);
1599cfeea807SEdgar E. Iglesias     tcg_temp_free_i32(t_ctrl);
160052065d8fSRichard Henderson     return true;
160152065d8fSRichard Henderson }
160252065d8fSRichard Henderson 
160352065d8fSRichard Henderson static bool trans_get(DisasContext *dc, arg_get *arg)
160452065d8fSRichard Henderson {
160552065d8fSRichard Henderson     return do_get(dc, arg->rd, 0, arg->imm, arg->ctrl);
160652065d8fSRichard Henderson }
160752065d8fSRichard Henderson 
160852065d8fSRichard Henderson static bool trans_getd(DisasContext *dc, arg_getd *arg)
160952065d8fSRichard Henderson {
161052065d8fSRichard Henderson     return do_get(dc, arg->rd, arg->rb, 0, arg->ctrl);
161152065d8fSRichard Henderson }
161252065d8fSRichard Henderson 
161352065d8fSRichard Henderson static bool do_put(DisasContext *dc, int ra, int rb, int imm, int ctrl)
161452065d8fSRichard Henderson {
161552065d8fSRichard Henderson     TCGv_i32 t_id, t_ctrl;
161652065d8fSRichard Henderson 
161752065d8fSRichard Henderson     if (trap_userspace(dc, true)) {
161852065d8fSRichard Henderson         return true;
161952065d8fSRichard Henderson     }
162052065d8fSRichard Henderson 
162152065d8fSRichard Henderson     t_id = tcg_temp_new_i32();
162252065d8fSRichard Henderson     if (rb) {
162352065d8fSRichard Henderson         tcg_gen_andi_i32(t_id, cpu_R[rb], 0xf);
162452065d8fSRichard Henderson     } else {
162552065d8fSRichard Henderson         tcg_gen_movi_i32(t_id, imm);
162652065d8fSRichard Henderson     }
162752065d8fSRichard Henderson 
162852065d8fSRichard Henderson     t_ctrl = tcg_const_i32(ctrl);
162952065d8fSRichard Henderson     gen_helper_put(t_id, t_ctrl, reg_for_read(dc, ra));
163052065d8fSRichard Henderson     tcg_temp_free_i32(t_id);
163152065d8fSRichard Henderson     tcg_temp_free_i32(t_ctrl);
163252065d8fSRichard Henderson     return true;
163352065d8fSRichard Henderson }
163452065d8fSRichard Henderson 
163552065d8fSRichard Henderson static bool trans_put(DisasContext *dc, arg_put *arg)
163652065d8fSRichard Henderson {
163752065d8fSRichard Henderson     return do_put(dc, arg->ra, 0, arg->imm, arg->ctrl);
163852065d8fSRichard Henderson }
163952065d8fSRichard Henderson 
164052065d8fSRichard Henderson static bool trans_putd(DisasContext *dc, arg_putd *arg)
164152065d8fSRichard Henderson {
164252065d8fSRichard Henderson     return do_put(dc, arg->ra, arg->rb, 0, arg->ctrl);
1643fcf5ef2aSThomas Huth }
1644fcf5ef2aSThomas Huth 
1645372122e3SRichard Henderson static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
1646fcf5ef2aSThomas Huth {
1647372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1648372122e3SRichard Henderson     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1649372122e3SRichard Henderson     int bound;
1650fcf5ef2aSThomas Huth 
16514b893631SRichard Henderson     dc->cfg = &cpu->cfg;
1652683a247eSRichard Henderson     dc->tb_flags = dc->base.tb->flags;
1653d7ecb757SRichard Henderson     dc->ext_imm = dc->base.tb->cs_base;
165420800179SRichard Henderson     dc->r0 = NULL;
165520800179SRichard Henderson     dc->r0_set = false;
1656287b1defSRichard Henderson     dc->mem_index = cpu_mmu_index(&cpu->env, false);
1657b9c58aabSRichard Henderson     dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER;
1658b9c58aabSRichard Henderson     dc->jmp_dest = -1;
1659fcf5ef2aSThomas Huth 
1660372122e3SRichard Henderson     bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
1661372122e3SRichard Henderson     dc->base.max_insns = MIN(dc->base.max_insns, bound);
1662fcf5ef2aSThomas Huth }
1663fcf5ef2aSThomas Huth 
1664372122e3SRichard Henderson static void mb_tr_tb_start(DisasContextBase *dcb, CPUState *cs)
1665fcf5ef2aSThomas Huth {
1666fcf5ef2aSThomas Huth }
1667fcf5ef2aSThomas Huth 
1668372122e3SRichard Henderson static void mb_tr_insn_start(DisasContextBase *dcb, CPUState *cs)
1669372122e3SRichard Henderson {
1670683a247eSRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1671683a247eSRichard Henderson 
1672683a247eSRichard Henderson     tcg_gen_insn_start(dc->base.pc_next, dc->tb_flags & ~MSR_TB_MASK);
1673683a247eSRichard Henderson     dc->insn_start = tcg_last_op();
1674372122e3SRichard Henderson }
1675fcf5ef2aSThomas Huth 
1676372122e3SRichard Henderson static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
1677372122e3SRichard Henderson {
1678372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1679372122e3SRichard Henderson     CPUMBState *env = cs->env_ptr;
168044d1432bSRichard Henderson     uint32_t ir;
1681372122e3SRichard Henderson 
1682372122e3SRichard Henderson     /* TODO: This should raise an exception, not terminate qemu. */
1683372122e3SRichard Henderson     if (dc->base.pc_next & 3) {
1684372122e3SRichard Henderson         cpu_abort(cs, "Microblaze: unaligned PC=%x\n",
1685372122e3SRichard Henderson                   (uint32_t)dc->base.pc_next);
1686fcf5ef2aSThomas Huth     }
1687fcf5ef2aSThomas Huth 
16886f9642d7SRichard Henderson     dc->tb_flags_to_set = 0;
16896f9642d7SRichard Henderson 
169044d1432bSRichard Henderson     ir = cpu_ldl_code(env, dc->base.pc_next);
169144d1432bSRichard Henderson     if (!decode(dc, ir)) {
1692921afa9dSRichard Henderson         trap_illegal(dc, true);
169344d1432bSRichard Henderson     }
169420800179SRichard Henderson 
169520800179SRichard Henderson     if (dc->r0) {
169620800179SRichard Henderson         tcg_temp_free_i32(dc->r0);
169720800179SRichard Henderson         dc->r0 = NULL;
169820800179SRichard Henderson         dc->r0_set = false;
169920800179SRichard Henderson     }
170020800179SRichard Henderson 
17016f9642d7SRichard Henderson     /* Discard the imm global when its contents cannot be used. */
17026f9642d7SRichard Henderson     if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) {
1703d7ecb757SRichard Henderson         tcg_gen_discard_i32(cpu_imm);
1704372122e3SRichard Henderson     }
17056f9642d7SRichard Henderson 
17061e521ce3SRichard Henderson     dc->tb_flags &= ~(IMM_FLAG | BIMM_FLAG | D_FLAG);
17076f9642d7SRichard Henderson     dc->tb_flags |= dc->tb_flags_to_set;
1708d4705ae0SRichard Henderson     dc->base.pc_next += 4;
1709fcf5ef2aSThomas Huth 
1710b9c58aabSRichard Henderson     if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
17113d35bcc2SRichard Henderson         /*
17123d35bcc2SRichard Henderson          * Finish any return-from branch.
17133d35bcc2SRichard Henderson          */
17143c745866SRichard Henderson         uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
17153c745866SRichard Henderson         if (unlikely(rt_ibe != 0)) {
17163c745866SRichard Henderson             dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
17173c745866SRichard Henderson             if (rt_ibe & DRTI_FLAG) {
1718fcf5ef2aSThomas Huth                 do_rti(dc);
17193c745866SRichard Henderson             } else if (rt_ibe & DRTB_FLAG) {
1720fcf5ef2aSThomas Huth                 do_rtb(dc);
17213c745866SRichard Henderson             } else {
1722fcf5ef2aSThomas Huth                 do_rte(dc);
1723372122e3SRichard Henderson             }
17243c745866SRichard Henderson         }
17253d35bcc2SRichard Henderson 
17263d35bcc2SRichard Henderson         /* Complete the branch, ending the TB. */
17273d35bcc2SRichard Henderson         switch (dc->base.is_jmp) {
17283d35bcc2SRichard Henderson         case DISAS_NORETURN:
17293d35bcc2SRichard Henderson             /*
17303d35bcc2SRichard Henderson              * E.g. illegal insn in a delay slot.  We've already exited
17313d35bcc2SRichard Henderson              * and will handle D_FLAG in mb_cpu_do_interrupt.
17323d35bcc2SRichard Henderson              */
17333d35bcc2SRichard Henderson             break;
17343d35bcc2SRichard Henderson         case DISAS_NEXT:
17353c745866SRichard Henderson             /*
17363c745866SRichard Henderson              * Normal insn a delay slot.
17373c745866SRichard Henderson              * However, the return-from-exception type insns should
17383c745866SRichard Henderson              * return to the main loop, as they have adjusted MSR.
17393c745866SRichard Henderson              */
17403c745866SRichard Henderson             dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
17413d35bcc2SRichard Henderson             break;
17423d35bcc2SRichard Henderson         case DISAS_EXIT_NEXT:
17433d35bcc2SRichard Henderson             /*
17443d35bcc2SRichard Henderson              * E.g. mts insn in a delay slot.  Continue with btarget,
17453d35bcc2SRichard Henderson              * but still return to the main loop.
17463d35bcc2SRichard Henderson              */
17473d35bcc2SRichard Henderson             dc->base.is_jmp = DISAS_EXIT_JUMP;
17483d35bcc2SRichard Henderson             break;
17493d35bcc2SRichard Henderson         default:
17503d35bcc2SRichard Henderson             g_assert_not_reached();
17513d35bcc2SRichard Henderson         }
1752372122e3SRichard Henderson     }
1753372122e3SRichard Henderson }
1754372122e3SRichard Henderson 
1755372122e3SRichard Henderson static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
1756372122e3SRichard Henderson {
1757372122e3SRichard Henderson     DisasContext *dc = container_of(dcb, DisasContext, base);
1758372122e3SRichard Henderson 
1759372122e3SRichard Henderson     if (dc->base.is_jmp == DISAS_NORETURN) {
1760372122e3SRichard Henderson         /* We have already exited the TB. */
1761372122e3SRichard Henderson         return;
1762372122e3SRichard Henderson     }
1763372122e3SRichard Henderson 
1764372122e3SRichard Henderson     t_sync_flags(dc);
1765372122e3SRichard Henderson 
1766372122e3SRichard Henderson     switch (dc->base.is_jmp) {
1767372122e3SRichard Henderson     case DISAS_TOO_MANY:
1768372122e3SRichard Henderson         gen_goto_tb(dc, 0, dc->base.pc_next);
1769372122e3SRichard Henderson         return;
1770372122e3SRichard Henderson 
177117e77796SRichard Henderson     case DISAS_EXIT:
1772f6278ca9SRichard Henderson         break;
1773f6278ca9SRichard Henderson     case DISAS_EXIT_NEXT:
1774f6278ca9SRichard Henderson         tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
1775f6278ca9SRichard Henderson         break;
1776f6278ca9SRichard Henderson     case DISAS_EXIT_JUMP:
1777f6278ca9SRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1778f6278ca9SRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1779f6278ca9SRichard Henderson         break;
1780372122e3SRichard Henderson 
1781372122e3SRichard Henderson     case DISAS_JUMP:
1782*fbafb3a4SRichard Henderson         if (dc->jmp_dest != -1 && !(tb_cflags(dc->base.tb) & CF_NO_GOTO_TB)) {
1783b9c58aabSRichard Henderson             /* Direct jump. */
1784b9c58aabSRichard Henderson             tcg_gen_discard_i32(cpu_btarget);
1785b9c58aabSRichard Henderson 
1786b9c58aabSRichard Henderson             if (dc->jmp_cond != TCG_COND_ALWAYS) {
1787b9c58aabSRichard Henderson                 /* Conditional direct jump. */
1788b9c58aabSRichard Henderson                 TCGLabel *taken = gen_new_label();
1789b9c58aabSRichard Henderson                 TCGv_i32 tmp = tcg_temp_new_i32();
1790b9c58aabSRichard Henderson 
1791b9c58aabSRichard Henderson                 /*
1792b9c58aabSRichard Henderson                  * Copy bvalue to a temp now, so we can discard bvalue.
1793b9c58aabSRichard Henderson                  * This can avoid writing bvalue to memory when the
1794b9c58aabSRichard Henderson                  * delay slot cannot raise an exception.
1795b9c58aabSRichard Henderson                  */
1796b9c58aabSRichard Henderson                 tcg_gen_mov_i32(tmp, cpu_bvalue);
1797b9c58aabSRichard Henderson                 tcg_gen_discard_i32(cpu_bvalue);
1798b9c58aabSRichard Henderson 
1799b9c58aabSRichard Henderson                 tcg_gen_brcondi_i32(dc->jmp_cond, tmp, 0, taken);
1800b9c58aabSRichard Henderson                 gen_goto_tb(dc, 1, dc->base.pc_next);
1801b9c58aabSRichard Henderson                 gen_set_label(taken);
1802b9c58aabSRichard Henderson             }
1803b9c58aabSRichard Henderson             gen_goto_tb(dc, 0, dc->jmp_dest);
1804b9c58aabSRichard Henderson             return;
1805b9c58aabSRichard Henderson         }
1806b9c58aabSRichard Henderson 
1807*fbafb3a4SRichard Henderson         /* Indirect jump (or direct jump w/ goto_tb disabled) */
1808b9c58aabSRichard Henderson         tcg_gen_mov_i32(cpu_pc, cpu_btarget);
1809b9c58aabSRichard Henderson         tcg_gen_discard_i32(cpu_btarget);
1810372122e3SRichard Henderson 
1811372122e3SRichard Henderson         if (unlikely(cs->singlestep_enabled)) {
1812372122e3SRichard Henderson             gen_raise_exception(dc, EXCP_DEBUG);
1813372122e3SRichard Henderson         } else {
18144059bd90SRichard Henderson             tcg_gen_lookup_and_goto_ptr();
1815372122e3SRichard Henderson         }
1816372122e3SRichard Henderson         return;
1817372122e3SRichard Henderson 
1818a2b80dbdSRichard Henderson     default:
1819a2b80dbdSRichard Henderson         g_assert_not_reached();
1820fcf5ef2aSThomas Huth     }
1821f6278ca9SRichard Henderson 
1822f6278ca9SRichard Henderson     /* Finish DISAS_EXIT_* */
1823f6278ca9SRichard Henderson     if (unlikely(cs->singlestep_enabled)) {
1824f6278ca9SRichard Henderson         gen_raise_exception(dc, EXCP_DEBUG);
1825f6278ca9SRichard Henderson     } else {
1826f6278ca9SRichard Henderson         tcg_gen_exit_tb(NULL, 0);
1827f6278ca9SRichard Henderson     }
1828fcf5ef2aSThomas Huth }
1829fcf5ef2aSThomas Huth 
1830372122e3SRichard Henderson static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
1831372122e3SRichard Henderson {
1832372122e3SRichard Henderson     qemu_log("IN: %s\n", lookup_symbol(dcb->pc_first));
1833372122e3SRichard Henderson     log_target_disas(cs, dcb->pc_first, dcb->tb->size);
1834fcf5ef2aSThomas Huth }
1835372122e3SRichard Henderson 
1836372122e3SRichard Henderson static const TranslatorOps mb_tr_ops = {
1837372122e3SRichard Henderson     .init_disas_context = mb_tr_init_disas_context,
1838372122e3SRichard Henderson     .tb_start           = mb_tr_tb_start,
1839372122e3SRichard Henderson     .insn_start         = mb_tr_insn_start,
1840372122e3SRichard Henderson     .translate_insn     = mb_tr_translate_insn,
1841372122e3SRichard Henderson     .tb_stop            = mb_tr_tb_stop,
1842372122e3SRichard Henderson     .disas_log          = mb_tr_disas_log,
1843372122e3SRichard Henderson };
1844372122e3SRichard Henderson 
1845372122e3SRichard Henderson void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
1846372122e3SRichard Henderson {
1847372122e3SRichard Henderson     DisasContext dc;
1848372122e3SRichard Henderson     translator_loop(&mb_tr_ops, &dc.base, cpu, tb, max_insns);
1849fcf5ef2aSThomas Huth }
1850fcf5ef2aSThomas Huth 
185190c84c56SMarkus Armbruster void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
1852fcf5ef2aSThomas Huth {
1853fcf5ef2aSThomas Huth     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
1854fcf5ef2aSThomas Huth     CPUMBState *env = &cpu->env;
18550c3da918SRichard Henderson     uint32_t iflags;
1856fcf5ef2aSThomas Huth     int i;
1857fcf5ef2aSThomas Huth 
18580c3da918SRichard Henderson     qemu_fprintf(f, "pc=0x%08x msr=0x%05x mode=%s(saved=%s) eip=%d ie=%d\n",
18590c3da918SRichard Henderson                  env->pc, env->msr,
18602e5282caSRichard Henderson                  (env->msr & MSR_UM) ? "user" : "kernel",
18612e5282caSRichard Henderson                  (env->msr & MSR_UMS) ? "user" : "kernel",
18622e5282caSRichard Henderson                  (bool)(env->msr & MSR_EIP),
18632e5282caSRichard Henderson                  (bool)(env->msr & MSR_IE));
18640c3da918SRichard Henderson 
18650c3da918SRichard Henderson     iflags = env->iflags;
18660c3da918SRichard Henderson     qemu_fprintf(f, "iflags: 0x%08x", iflags);
18670c3da918SRichard Henderson     if (iflags & IMM_FLAG) {
18680c3da918SRichard Henderson         qemu_fprintf(f, " IMM(0x%08x)", env->imm);
18692ead1b18SJoe Komlodi     }
18700c3da918SRichard Henderson     if (iflags & BIMM_FLAG) {
18710c3da918SRichard Henderson         qemu_fprintf(f, " BIMM");
18720c3da918SRichard Henderson     }
18730c3da918SRichard Henderson     if (iflags & D_FLAG) {
1874b9c58aabSRichard Henderson         qemu_fprintf(f, " D(btarget=0x%08x)", env->btarget);
18750c3da918SRichard Henderson     }
18760c3da918SRichard Henderson     if (iflags & DRTI_FLAG) {
18770c3da918SRichard Henderson         qemu_fprintf(f, " DRTI");
18780c3da918SRichard Henderson     }
18790c3da918SRichard Henderson     if (iflags & DRTE_FLAG) {
18800c3da918SRichard Henderson         qemu_fprintf(f, " DRTE");
18810c3da918SRichard Henderson     }
18820c3da918SRichard Henderson     if (iflags & DRTB_FLAG) {
18830c3da918SRichard Henderson         qemu_fprintf(f, " DRTB");
18840c3da918SRichard Henderson     }
18850c3da918SRichard Henderson     if (iflags & ESR_ESS_FLAG) {
18860c3da918SRichard Henderson         qemu_fprintf(f, " ESR_ESS(0x%04x)", iflags & ESR_ESS_MASK);
18872ead1b18SJoe Komlodi     }
1888fcf5ef2aSThomas Huth 
18890c3da918SRichard Henderson     qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n"
189019f27b6cSRichard Henderson                  "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n",
18910c3da918SRichard Henderson                  env->esr, env->fsr, env->btr, env->edr,
18920c3da918SRichard Henderson                  env->ear, env->slr, env->shr);
18930c3da918SRichard Henderson 
18940c3da918SRichard Henderson     for (i = 0; i < 32; i++) {
18950c3da918SRichard Henderson         qemu_fprintf(f, "r%2.2d=%08x%c",
18960c3da918SRichard Henderson                      i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
18970c3da918SRichard Henderson     }
18980c3da918SRichard Henderson     qemu_fprintf(f, "\n");
1899fcf5ef2aSThomas Huth }
1900fcf5ef2aSThomas Huth 
1901fcf5ef2aSThomas Huth void mb_tcg_init(void)
1902fcf5ef2aSThomas Huth {
1903480d29a8SRichard Henderson #define R(X)  { &cpu_R[X], offsetof(CPUMBState, regs[X]), "r" #X }
1904480d29a8SRichard Henderson #define SP(X) { &cpu_##X, offsetof(CPUMBState, X), #X }
1905fcf5ef2aSThomas Huth 
1906480d29a8SRichard Henderson     static const struct {
1907480d29a8SRichard Henderson         TCGv_i32 *var; int ofs; char name[8];
1908480d29a8SRichard Henderson     } i32s[] = {
1909e47c2231SRichard Henderson         /*
1910e47c2231SRichard Henderson          * Note that r0 is handled specially in reg_for_read
1911e47c2231SRichard Henderson          * and reg_for_write.  Nothing should touch cpu_R[0].
1912e47c2231SRichard Henderson          * Leave that element NULL, which will assert quickly
1913e47c2231SRichard Henderson          * inside the tcg generator functions.
1914e47c2231SRichard Henderson          */
1915e47c2231SRichard Henderson                R(1),  R(2),  R(3),  R(4),  R(5),  R(6),  R(7),
1916480d29a8SRichard Henderson         R(8),  R(9),  R(10), R(11), R(12), R(13), R(14), R(15),
1917480d29a8SRichard Henderson         R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
1918480d29a8SRichard Henderson         R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
1919480d29a8SRichard Henderson 
1920480d29a8SRichard Henderson         SP(pc),
1921480d29a8SRichard Henderson         SP(msr),
19221074c0fbSRichard Henderson         SP(msr_c),
1923480d29a8SRichard Henderson         SP(imm),
1924480d29a8SRichard Henderson         SP(iflags),
1925b9c58aabSRichard Henderson         SP(bvalue),
1926480d29a8SRichard Henderson         SP(btarget),
1927480d29a8SRichard Henderson         SP(res_val),
1928480d29a8SRichard Henderson     };
1929480d29a8SRichard Henderson 
1930480d29a8SRichard Henderson #undef R
1931480d29a8SRichard Henderson #undef SP
1932480d29a8SRichard Henderson 
1933480d29a8SRichard Henderson     for (int i = 0; i < ARRAY_SIZE(i32s); ++i) {
1934480d29a8SRichard Henderson         *i32s[i].var =
1935480d29a8SRichard Henderson           tcg_global_mem_new_i32(cpu_env, i32s[i].ofs, i32s[i].name);
1936fcf5ef2aSThomas Huth     }
193776e8187dSRichard Henderson 
1938480d29a8SRichard Henderson     cpu_res_addr =
1939480d29a8SRichard Henderson         tcg_global_mem_new(cpu_env, offsetof(CPUMBState, res_addr), "res_addr");
1940fcf5ef2aSThomas Huth }
1941fcf5ef2aSThomas Huth 
1942fcf5ef2aSThomas Huth void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb,
1943fcf5ef2aSThomas Huth                           target_ulong *data)
1944fcf5ef2aSThomas Huth {
194576e8187dSRichard Henderson     env->pc = data[0];
1946683a247eSRichard Henderson     env->iflags = data[1];
1947fcf5ef2aSThomas Huth }
1948